Merge "[SettingsProvider] Auto disable ringtone sync"
diff --git a/Android.mk b/Android.mk
index 21bd76b..2539c3d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -346,6 +346,7 @@
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
 	core/java/com/android/internal/backup/IObbBackupService.aidl \
+	core/java/com/android/internal/font/IFontManager.aidl \
 	core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
 	core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
 	core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index 3a7f945..200f92f 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -8,7 +8,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
-    apct-perftests-utils
+    apct-perftests-utils \
+    legacy-android-test
 
 LOCAL_PACKAGE_NAME := CorePerfTests
 
diff --git a/api/current.txt b/api/current.txt
index b9cd7d0..71aba70 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -83,6 +83,7 @@
     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";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+    field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
     field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -113,6 +114,7 @@
     field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
     field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
     field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
+    field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
     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";
@@ -201,6 +203,8 @@
 
   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
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -361,6 +365,7 @@
     field public static final int centerMedium = 16842959; // 0x10100cf
     field public static final int centerX = 16843170; // 0x10101a2
     field public static final int centerY = 16843171; // 0x10101a3
+    field public static final int certDigest = 16844106; // 0x101054a
     field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
     field public static final int checkMark = 16843016; // 0x1010108
     field public static final int checkMarkTint = 16843943; // 0x10104a7
@@ -755,7 +760,6 @@
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
     field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
-    field public static final int keyboardNavigationSection = 16844097; // 0x1010541
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
@@ -905,7 +909,6 @@
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
-    field public static final int nextSectionForward = 16844099; // 0x1010543
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -989,6 +992,7 @@
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int previewImage = 16843482; // 0x10102da
+    field public static final int primaryContentAlpha = 16843367; // 0x1010267
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
@@ -1052,6 +1056,7 @@
     field public static final int resizeable = 16843405; // 0x101028d
     field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
+    field public static final int restartOnConfigChanges = 16844105; // 0x1010549
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
@@ -1376,7 +1381,7 @@
     field public static final int toYDelta = 16843209; // 0x10101c9
     field public static final int toYScale = 16843205; // 0x10101c5
     field public static final int toolbarStyle = 16843946; // 0x10104aa
-    field public static final int tooltip = 16844084; // 0x1010534
+    field public static final int tooltipText = 16844084; // 0x1010534
     field public static final int top = 16843182; // 0x10101ae
     field public static final int topBright = 16842955; // 0x10100cb
     field public static final int topDark = 16842951; // 0x10100c7
@@ -1435,7 +1440,7 @@
     field public static final int viewportWidth = 16843778; // 0x1010402
     field public static final int visibility = 16842972; // 0x10100dc
     field public static final int visible = 16843156; // 0x1010194
-    field public static final int visibleToEphemeral = 16844095; // 0x101053f
+    field public static final int visibleToInstantApps = 16844095; // 0x101053f
     field public static final int vmSafeMode = 16843448; // 0x10102b8
     field public static final int voiceIcon = 16843908; // 0x1010484
     field public static final int voiceLanguage = 16843349; // 0x1010255
@@ -1812,6 +1817,7 @@
     field public static final int tabs = 16908307; // 0x1020013
     field public static final int text1 = 16908308; // 0x1020014
     field public static final int text2 = 16908309; // 0x1020015
+    field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
     field public static final int undo = 16908338; // 0x1020032
@@ -2878,15 +2884,18 @@
   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, int[]);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, 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;
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     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 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);
     method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
     method public android.accounts.Account[] getAccountsByTypeForPackage(java.lang.String, java.lang.String);
@@ -2897,13 +2906,11 @@
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
-    method public int[] getRequestingUidsForType(java.lang.String);
+    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);
-    method public boolean isAccountVisible(android.accounts.Account, int);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method public boolean makeAccountVisible(android.accounts.Account, int);
     method public static deprecated android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -2911,9 +2918,9 @@
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean removeAccountExplicitly(android.accounts.Account);
-    method public boolean removeAccountVisibility(android.accounts.Account, int);
     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 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);
@@ -2952,7 +2959,14 @@
     field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
-    field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+    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 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
+    field public static final int VISIBILITY_USER_MANAGED_VISIBLE = 2; // 0x2
+    field public static final int VISIBILITY_VISIBLE = 1; // 0x1
   }
 
   public abstract interface AccountManagerCallback<V> {
@@ -3490,8 +3504,7 @@
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void enterPictureInPictureMode();
-    method public void enterPictureInPictureMode(float);
-    method public void enterPictureInPictureModeOnMoveToBackground(boolean);
+    method public boolean enterPictureInPictureMode(android.app.PictureInPictureArgs);
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3524,7 +3537,6 @@
     method public int getRequestedOrientation();
     method public final android.view.SearchEvent getSearchEvent();
     method public int getTaskId();
-    method public android.text.TextAssistant getTextAssistant();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
     method public android.app.VoiceInteractor getVoiceInteractor();
@@ -3664,8 +3676,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
-    method public void setPictureInPictureActions(java.util.List<android.app.RemoteAction>);
-    method public void setPictureInPictureAspectRatio(float);
+    method public void setPictureInPictureArgs(android.app.PictureInPictureArgs);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3675,7 +3686,6 @@
     method public final void setResult(int, android.content.Intent);
     method public final deprecated void setSecondaryProgress(int);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
-    method public void setTextAssistant(android.text.TextAssistant);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public deprecated void setTitleColor(int);
@@ -4591,6 +4601,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -4826,11 +4837,13 @@
   public static class Instrumentation.ActivityMonitor {
     ctor public Instrumentation.ActivityMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     ctor public Instrumentation.ActivityMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    ctor public Instrumentation.ActivityMonitor();
     method public final android.content.IntentFilter getFilter();
     method public final int getHits();
     method public final android.app.Activity getLastActivity();
     method public final android.app.Instrumentation.ActivityResult getResult();
     method public final boolean isBlocking();
+    method public android.app.Instrumentation.ActivityResult onMatchIntent(android.content.Intent);
     method public final android.app.Activity waitForActivity();
     method public final android.app.Activity waitForActivityWithTimeout(long);
   }
@@ -5025,6 +5038,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5108,6 +5122,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
+    method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
@@ -5397,7 +5412,6 @@
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
-    method public boolean isAllowed();
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
@@ -5435,6 +5449,7 @@
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
+    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
@@ -5520,6 +5535,17 @@
     method public abstract void onSendFinished(android.app.PendingIntent, android.content.Intent, int, java.lang.String, android.os.Bundle);
   }
 
+  public final class PictureInPictureArgs implements android.os.Parcelable {
+    ctor public PictureInPictureArgs();
+    ctor public PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
+    method public android.app.PictureInPictureArgs clone();
+    method public int describeContents();
+    method public void setActions(java.util.List<android.app.RemoteAction>);
+    method public void setAspectRatio(float);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
+  }
+
   public class Presentation extends android.app.Dialog {
     ctor public Presentation(android.content.Context, android.view.Display);
     ctor public Presentation(android.content.Context, android.view.Display, int);
@@ -5556,6 +5582,18 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
+    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+    method public int describeContents();
+    method public android.app.PendingIntent getUserAction();
+    method public java.lang.CharSequence getUserActionTitle();
+    method public java.lang.CharSequence getUserMessage();
+    method public void showAsDialog(android.app.Activity);
+    method public void showAsNotification(android.content.Context);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
+  }
+
   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);
     method public android.app.RemoteAction clone();
@@ -5573,14 +5611,18 @@
   }
 
   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);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5592,6 +5634,7 @@
     method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
@@ -6107,6 +6150,7 @@
     method public int getPasswordMinimumSymbols(android.content.ComponentName);
     method public int getPasswordMinimumUpperCase(android.content.ComponentName);
     method public int getPasswordQuality(android.content.ComponentName);
+    method public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(android.content.ComponentName);
     method public int getPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int getPermissionPolicy(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
@@ -6128,6 +6172,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isBackupServiceEnabled(android.content.ComponentName);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceOwnerApp(java.lang.String);
     method public boolean isLockTaskPermitted(java.lang.String);
@@ -6158,6 +6203,7 @@
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
+    method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
@@ -6328,6 +6374,17 @@
     field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
   }
 
+  public final class SystemUpdateInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getReceivedTime();
+    method public int getSecurityPatchState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdateInfo> CREATOR;
+    field public static final int SECURITY_PATCH_STATE_FALSE = 1; // 0x1
+    field public static final int SECURITY_PATCH_STATE_TRUE = 2; // 0x2
+    field public static final int SECURITY_PATCH_STATE_UNKNOWN = 0; // 0x0
+  }
+
   public class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -7911,6 +7968,7 @@
     ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
     ctor public ClipData(android.content.ClipData);
     method public void addItem(android.content.ClipData.Item);
+    method public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
     method public int describeContents();
     method public android.content.ClipDescription getDescription();
     method public android.content.ClipData.Item getItemAt(int);
@@ -8429,6 +8487,7 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -8999,10 +9058,10 @@
     field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
@@ -9515,6 +9574,7 @@
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
     method public final int getThemeResource();
+    field public static final int CONFIG_COLORIMETRY = 16384; // 0x4000
     field public static final int CONFIG_DENSITY = 4096; // 0x1000
     field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
     field public static final int CONFIG_KEYBOARD = 16; // 0x10
@@ -9786,7 +9846,10 @@
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
+    method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
@@ -9821,7 +9884,7 @@
     method public boolean accept(android.os.Bundle);
     method public boolean accept();
     method public int describeContents();
-    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo();
+    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo(android.content.Context);
     method public int getRequestType();
     method public android.content.pm.ShortcutInfo getShortcutInfo();
     method public boolean isValid();
@@ -9890,6 +9953,7 @@
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
     method public void uninstall(java.lang.String, android.content.IntentSender);
+    method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender);
     method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void updateSessionAppIcon(int, android.graphics.Bitmap);
     method public void updateSessionAppLabel(int, java.lang.CharSequence);
@@ -10036,6 +10100,7 @@
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInstaller getPackageInstaller();
     method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] getPackagesForUid(int);
@@ -10050,6 +10115,7 @@
     method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -10208,6 +10274,7 @@
     field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
     field public static final int VERIFICATION_ALLOW = 1; // 0x1
     field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
+    field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
   }
 
   public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -10347,6 +10414,20 @@
     field public java.lang.String permission;
   }
 
+  public final class SharedLibraryInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.pm.VersionedPackage getDeclaringPackage();
+    method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
+    method public java.lang.String getName();
+    method public int getVersion();
+    method public boolean isBuiltin();
+    method public boolean isDynamic();
+    method public boolean isStatic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR;
+    field public static final int VERSION_UNDEFINED = -1; // 0xffffffff
+  }
+
   public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getActivity();
@@ -10390,6 +10471,7 @@
 
   public class ShortcutManager {
     method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
     method public void disableShortcuts(java.util.List<java.lang.String>);
     method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
     method public void enableShortcuts(java.util.List<java.lang.String>);
@@ -10421,6 +10503,15 @@
     field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR;
   }
 
+  public final class VersionedPackage implements android.os.Parcelable {
+    ctor public VersionedPackage(java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public long getVersionCode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR;
+  }
+
 }
 
 package android.content.res {
@@ -10506,7 +10597,9 @@
     method public int getLayoutDirection();
     method public android.os.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
+    method public boolean isScreenHdr();
     method public boolean isScreenRound();
+    method public boolean isScreenWideColorGamut();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
@@ -10516,6 +10609,16 @@
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int COLORIMETRY_HDR_MASK = 12; // 0xc
+    field public static final int COLORIMETRY_HDR_NO = 4; // 0x4
+    field public static final int COLORIMETRY_HDR_SHIFT = 2; // 0x2
+    field public static final int COLORIMETRY_HDR_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_HDR_YES = 8; // 0x8
+    field public static final int COLORIMETRY_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 1; // 0x1
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 2; // 0x2
     field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
     field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
     field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
@@ -10581,6 +10684,7 @@
     field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
     field public static final int UI_MODE_TYPE_VR_HEADSET = 7; // 0x7
     field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
+    field public int colorimetry;
     field public int densityDpi;
     field public float fontScale;
     field public int hardKeyboardHidden;
@@ -10635,6 +10739,7 @@
     method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
+    method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
     method public float getFraction(int, int, int);
     method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
     method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;
@@ -12121,15 +12226,57 @@
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
     method public static void RGBToHSV(int, int, int, float[]);
+    method public float alpha();
+    method public static float alpha(long);
     method public static int alpha(int);
     method public static int argb(int, int, int, int);
+    method public static int argb(float, float, float, float);
+    method public float blue();
+    method public static float blue(long);
     method public static int blue(int);
+    method public static android.graphics.ColorSpace colorSpace(long);
     method public static void colorToHSV(int, float[]);
+    method public android.graphics.Color convert(android.graphics.ColorSpace);
+    method public static long convert(int, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace.Connector);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
+    method public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(int);
+    method public int getComponentCount();
+    method public float[] getComponents();
+    method public android.graphics.ColorSpace.Model getModel();
+    method public float green();
+    method public static float green(long);
     method public static int green(int);
+    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public boolean isSrgb();
+    method public static boolean isSrgb(long);
+    method public boolean isWideGamut();
+    method public static boolean isWideGamut(long);
+    method public float luminance();
+    method public static float luminance(long);
     method public static float luminance(int);
+    method public long pack();
+    method public static long pack(int);
+    method public static long pack(float, float, float);
+    method public static long pack(float, float, float, float);
+    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
     method public static int parseColor(java.lang.String);
+    method public float red();
+    method public static float red(long);
     method public static int red(int);
     method public static int rgb(int, int, int);
+    method public static int rgb(float, float, float);
+    method public int toArgb();
+    method public static int toArgb(long);
+    method public static android.graphics.Color valueOf(int);
+    method public static android.graphics.Color valueOf(long);
+    method public static android.graphics.Color valueOf(float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
+    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
     field public static final int BLACK = -16777216; // 0xff000000
     field public static final int BLUE = -16776961; // 0xff0000ff
     field public static final int CYAN = -16711681; // 0xff00ffff
@@ -12201,7 +12348,7 @@
     field public static final float[] ILLUMINANT_D65;
     field public static final float[] ILLUMINANT_D75;
     field public static final float[] ILLUMINANT_E;
-    field public static final int MAX_ID = 64; // 0x40
+    field public static final int MAX_ID = 63; // 0x3f
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
@@ -12524,7 +12671,6 @@
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
     method public float getFontSpacing();
-    method public java.lang.String getFontVariationSettings();
     method public int getHinting();
     method public float getLetterSpacing();
     method public android.graphics.MaskFilter getMaskFilter();
@@ -12582,7 +12728,6 @@
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(java.lang.String);
-    method public void setFontVariationSettings(java.lang.String);
     method public void setHinting(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
@@ -13981,6 +14126,37 @@
     method public float getZ();
   }
 
+  public final class HardwareBuffer implements android.os.Parcelable {
+    method public static android.hardware.HardwareBuffer create(int, int, int, int, long);
+    method public int describeContents();
+    method public void destroy();
+    method public int getFormat();
+    method public int getHeight();
+    method public int getLayers();
+    method public long getUsage();
+    method public int getWidth();
+    method public boolean isDestroyed();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
+    field public static final int RGBA_8888 = 1; // 0x1
+    field public static final int RGBA_FP16 = 5; // 0x5
+    field public static final int RGBX_8888 = 2; // 0x2
+    field public static final int RGB_565 = 4; // 0x4
+    field public static final int RGB_888 = 3; // 0x3
+    field public static final long USAGE0_CPU_READ = 2L; // 0x2L
+    field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L
+    field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L
+    field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L
+    field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L
+    field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L
+    field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L
+    field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L
+    field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L
+    field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L
+    field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L
+    field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L
+  }
+
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
@@ -19686,6 +19862,7 @@
     method public double getAccumulatedDeltaRangeMeters();
     method public int getAccumulatedDeltaRangeState();
     method public double getAccumulatedDeltaRangeUncertaintyMeters();
+    method public double getAutomaticGainControlLevelInDb();
     method public long getCarrierCycles();
     method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
@@ -19701,6 +19878,7 @@
     method public int getState();
     method public int getSvid();
     method public double getTimeOffsetNanos();
+    method public boolean hasAutomaticGainControlLevelInDb();
     method public boolean hasCarrierCycles();
     method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
@@ -19724,11 +19902,13 @@
     field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
     field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
     field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
     field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
     field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
     field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
     field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
     field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
     field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
@@ -19785,12 +19965,14 @@
 
   public final class GnssStatus {
     method public float getAzimuthDegrees(int);
+    method public float getCarrierFrequencyHz(int);
     method public float getCn0DbHz(int);
     method public int getConstellationType(int);
     method public float getElevationDegrees(int);
     method public int getSatelliteCount();
     method public int getSvid(int);
     method public boolean hasAlmanacData(int);
+    method public boolean hasCarrierFrequency(int);
     method public boolean hasEphemerisData(int);
     method public boolean usedInFix(int);
     field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
@@ -19851,34 +20033,46 @@
     method public float getAccuracy();
     method public double getAltitude();
     method public float getBearing();
+    method public float getBearingAccuracyDegrees();
     method public long getElapsedRealtimeNanos();
     method public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
     method public java.lang.String getProvider();
     method public float getSpeed();
+    method public float getSpeedAccuracyMetersPerSecond();
     method public long getTime();
+    method public float getVerticalAccuracyMeters();
     method public boolean hasAccuracy();
     method public boolean hasAltitude();
     method public boolean hasBearing();
+    method public boolean hasBearingAccuracy();
     method public boolean hasSpeed();
+    method public boolean hasSpeedAccuracy();
+    method public boolean hasVerticalAccuracy();
     method public boolean isFromMockProvider();
     method public void removeAccuracy();
     method public void removeAltitude();
     method public void removeBearing();
+    method public void removeBearingAccuracy();
     method public void removeSpeed();
+    method public void removeSpeedAccuracy();
+    method public void removeVerticalAccuracy();
     method public void reset();
     method public void set(android.location.Location);
     method public void setAccuracy(float);
     method public void setAltitude(double);
     method public void setBearing(float);
+    method public void setBearingAccuracyDegrees(float);
     method public void setElapsedRealtimeNanos(long);
     method public void setExtras(android.os.Bundle);
     method public void setLatitude(double);
     method public void setLongitude(double);
     method public void setProvider(java.lang.String);
     method public void setSpeed(float);
+    method public void setSpeedAccuracyMetersPerSecond(float);
     method public void setTime(long);
+    method public void setVerticalAccuracyMeters(float);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
     field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -21848,6 +22042,8 @@
     method public void setLocation(float, float);
     method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
     method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
+    method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalStateException;
+    method public void setNextOutputFile(java.lang.String) throws java.io.IOException, java.lang.IllegalStateException;
     method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener);
     method public void setOnInfoListener(android.media.MediaRecorder.OnInfoListener);
     method public void setOrientationHint(int);
@@ -21866,7 +22062,9 @@
     field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
+    field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802; // 0x322
     field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801; // 0x321
+    field public static final int MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803; // 0x323
     field public static final int MEDIA_RECORDER_INFO_UNKNOWN = 1; // 0x1
   }
 
@@ -24388,6 +24586,7 @@
   public class TrafficStats {
     ctor public TrafficStats();
     method public static void clearThreadStatsTag();
+    method public static int getAndSetThreadStatsTag(int);
     method public static long getMobileRxBytes();
     method public static long getMobileRxPackets();
     method public static long getMobileTxBytes();
@@ -29846,6 +30045,15 @@
     field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
   }
 
+  public abstract class ProxyFileDescriptorCallback {
+    ctor public ProxyFileDescriptorCallback();
+    method public void onFsync() throws android.system.ErrnoException;
+    method public long onGetSize() throws android.system.ErrnoException;
+    method public int onRead(long, int, byte[]) throws android.system.ErrnoException;
+    method public abstract void onRelease();
+    method public int onWrite(long, int, byte[]) throws android.system.ErrnoException;
+  }
+
   public class RecoverySystem {
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
@@ -29960,6 +30168,7 @@
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
+    method public android.os.StrictMode.VmPolicy.Builder detectUntaggedSockets();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
@@ -30256,13 +30465,22 @@
   }
 
   public class StorageManager {
+    method public long getCacheQuotaBytes();
+    method public long getCacheSizeBytes();
+    method public long getExternalCacheQuotaBytes();
+    method public long getExternalCacheSizeBytes();
     method public java.lang.String getMountedObbPath(java.lang.String);
     method public android.os.storage.StorageVolume getPrimaryStorageVolume();
     method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
     method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method public boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
+    method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
     method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+    method public void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
+    method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
     field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
   }
@@ -32360,7 +32578,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -32470,8 +32688,10 @@
   public static final class ContactsContract.ProviderStatus {
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
+    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -32617,6 +32837,7 @@
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -32661,6 +32882,7 @@
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+    field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -32694,6 +32916,7 @@
     ctor public DocumentsProvider();
     method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
     method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
@@ -35146,6 +35369,7 @@
     field public static final int PURPOSE_ENCRYPT = 1; // 0x1
     field public static final int PURPOSE_SIGN = 4; // 0x4
     field public static final int PURPOSE_VERIFY = 8; // 0x8
+    field public static final int PURPOSE_WRAP_KEY = 16; // 0x10
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
   }
@@ -35205,6 +35429,7 @@
     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 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 {
@@ -35410,7 +35635,6 @@
     field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
     field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -37084,6 +37308,7 @@
     method public void onReject();
     method public void onReject(java.lang.String);
     method public void onSeparate();
+    method public void onShowIncomingCallUi();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
@@ -37095,6 +37320,7 @@
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
+    method public final void setAudioRoute(int);
     method public final void setCallerDisplayName(java.lang.String, int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
@@ -37143,6 +37369,7 @@
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
+    field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -37210,7 +37437,9 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -37323,6 +37552,7 @@
     field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
@@ -37504,6 +37734,8 @@
     method public boolean handleMmi(java.lang.String);
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
+    method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
+    method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
@@ -37514,7 +37746,7 @@
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT";
     field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
-    field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
+    field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
@@ -37617,7 +37849,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -37709,9 +37942,13 @@
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -38927,6 +39164,7 @@
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public android.content.ComponentName startService(android.content.Intent);
+    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
     method public boolean stopService(android.content.Intent);
     method public void unbindService(android.content.ServiceConnection);
     method public void unregisterReceiver(android.content.BroadcastReceiver);
@@ -39027,6 +39265,7 @@
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
     method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] getPackagesForUid(int);
@@ -39041,6 +39280,7 @@
     method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
     method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public java.lang.String[] getSystemSharedLibraryNames();
     method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -39270,6 +39510,65 @@
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
+  public final class FontConfig implements android.os.Parcelable {
+    ctor public FontConfig();
+    ctor public FontConfig(android.text.FontConfig);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method public java.util.List<android.text.FontConfig.Family> getFamilies();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
+  }
+
+  public static final class FontConfig.Alias implements android.os.Parcelable {
+    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getName();
+    method public java.lang.String getToName();
+    method public int getWeight();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
+  }
+
+  public static final class FontConfig.Axis implements android.os.Parcelable {
+    ctor public FontConfig.Axis(int, float);
+    method public int describeContents();
+    method public float getStyleValue();
+    method public int getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
+  }
+
+  public static final class FontConfig.Family implements android.os.Parcelable {
+    ctor public FontConfig.Family(java.lang.String, java.util.List<android.text.FontConfig.Font>, java.lang.String, java.lang.String);
+    ctor public FontConfig.Family(android.text.FontConfig.Family);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Font> getFonts();
+    method public java.lang.String getLanguage();
+    method public java.lang.String getName();
+    method public java.lang.String getVariant();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
+  }
+
+  public static final class FontConfig.Font implements android.os.Parcelable {
+    ctor public FontConfig.Font(java.lang.String, int, java.util.List<android.text.FontConfig.Axis>, int, boolean);
+    ctor public FontConfig.Font(android.text.FontConfig.Font);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Axis> getAxes();
+    method public android.os.ParcelFileDescriptor getFd();
+    method public java.lang.String getFontName();
+    method public int getTtcIndex();
+    method public int getWeight();
+    method public boolean isItalic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
+  }
+
+  public final class FontManager {
+    method public android.text.FontConfig getSystemFonts();
+  }
+
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
@@ -39625,22 +39924,6 @@
     method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
   }
 
-  public abstract interface TextAssistant {
-    method public abstract void addLinks(android.text.Spannable, int);
-    method public abstract android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
-  public class TextClassification {
-    ctor public TextClassification();
-    method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence();
-  }
-
-  public final class TextClassificationManager implements android.text.TextAssistant {
-    method public void addLinks(android.text.Spannable, int);
-    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
-    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -39656,13 +39939,6 @@
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
-  public final class TextLanguage {
-    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public int getEndIndex();
-    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
-    method public int getStartIndex();
-  }
-
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -39675,13 +39951,6 @@
     field public int linkColor;
   }
 
-  public class TextSelection {
-    ctor public TextSelection();
-    method public int getSelectionEndIndex();
-    method public int getSelectionStartIndex();
-    method public android.text.TextClassification getTextClassification();
-  }
-
   public class TextUtils {
     method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String);
     method public static java.lang.CharSequence concat(java.lang.CharSequence...);
@@ -41935,7 +42204,9 @@
     method public android.view.Display.Mode[] getSupportedModes();
     method public deprecated float[] getSupportedRefreshRates();
     method public deprecated int getWidth();
+    method public boolean isHdr();
     method public boolean isValid();
+    method public boolean isWideColorGamut();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
     field public static final int FLAG_PRESENTATION = 8; // 0x8
     field public static final int FLAG_PRIVATE = 4; // 0x4
@@ -42004,7 +42275,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
-    method public android.view.View findNextKeyboardNavigationGroup(int, android.view.View, android.view.View, int);
+    method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -42789,7 +43060,7 @@
     method public abstract android.view.SubMenu getSubMenu();
     method public abstract java.lang.CharSequence getTitle();
     method public abstract java.lang.CharSequence getTitleCondensed();
-    method public default java.lang.CharSequence getTooltip();
+    method public default java.lang.CharSequence getTooltipText();
     method public abstract boolean hasSubMenu();
     method public abstract boolean isActionViewExpanded();
     method public abstract boolean isCheckable();
@@ -42816,7 +43087,7 @@
     method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
     method public abstract android.view.MenuItem setTitle(int);
     method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
-    method public default android.view.MenuItem setTooltip(java.lang.CharSequence);
+    method public default android.view.MenuItem setTooltipText(java.lang.CharSequence);
     method public abstract android.view.MenuItem setVisible(boolean);
     field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
@@ -43302,7 +43573,7 @@
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     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 addKeyboardNavigationGroups(int, java.util.Collection<android.view.View>, int);
+    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43466,7 +43737,6 @@
     method public int getNextFocusLeftId();
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
-    method public int getNextSectionForwardId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method public int getOverScrollMode();
@@ -43510,7 +43780,8 @@
     method public java.lang.Object getTag(int);
     method public int getTextAlignment();
     method public int getTextDirection();
-    method public final java.lang.CharSequence getTooltip();
+    method public final deprecated java.lang.CharSequence getTooltip();
+    method public final java.lang.CharSequence getTooltipText();
     method public final int getTop();
     method protected float getTopFadingEdgeStrength();
     method protected int getTopPaddingOffset();
@@ -43571,7 +43842,6 @@
     method public boolean isInLayout();
     method public boolean isInTouchMode();
     method public final boolean isKeyboardNavigationCluster();
-    method public final boolean isKeyboardNavigationSection();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
@@ -43594,7 +43864,7 @@
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
-    method public android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
@@ -43744,7 +44014,6 @@
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
     method public void setKeyboardNavigationCluster(boolean);
-    method public void setKeyboardNavigationSection(boolean);
     method public void setLabelFor(int);
     method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
@@ -43762,7 +44031,6 @@
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
-    method public void setNextSectionForwardId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -43811,7 +44079,8 @@
     method public void setTag(int, java.lang.Object);
     method public void setTextAlignment(int);
     method public void setTextDirection(int);
-    method public final void setTooltip(java.lang.CharSequence);
+    method public final deprecated void setTooltip(java.lang.CharSequence);
+    method public final void setTooltipText(java.lang.CharSequence);
     method public final void setTop(int);
     method public void setTouchDelegate(android.view.TouchDelegate);
     method public final void setTransitionName(java.lang.String);
@@ -43888,8 +44157,6 @@
     field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
     field public static final int INVISIBLE = 4; // 0x4
     field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
-    field public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; // 0x1
-    field public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; // 0x2
     field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
     field public static final int LAYER_TYPE_NONE = 0; // 0x0
     field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
@@ -44408,7 +44675,7 @@
     method public abstract boolean isLayoutRequested();
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
-    method public abstract android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract boolean onNestedPreFling(android.view.View, float, float);
@@ -46195,6 +46462,83 @@
 
 }
 
+package android.view.textclassifier {
+
+  public abstract interface LinksInfo {
+    method public abstract boolean apply(java.lang.CharSequence);
+  }
+
+  public final class TextClassificationManager {
+    method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.view.textclassifier.TextClassifier getDefaultTextClassifier();
+  }
+
+  public final class TextClassificationResult {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public android.view.View.OnClickListener getOnClickListener();
+    method public java.lang.String getText();
+  }
+
+  public static final class TextClassificationResult.Builder {
+    ctor public TextClassificationResult.Builder();
+    method public android.view.textclassifier.TextClassificationResult build();
+    method public android.view.textclassifier.TextClassificationResult.Builder setEntityType(java.lang.String, float);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIntent(android.content.Intent);
+    method public android.view.textclassifier.TextClassificationResult.Builder setLabel(java.lang.String);
+    method public android.view.textclassifier.TextClassificationResult.Builder setOnClickListener(android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassificationResult.Builder setText(java.lang.String);
+  }
+
+  public abstract interface TextClassifier {
+    method public abstract android.view.textclassifier.LinksInfo getLinks(java.lang.CharSequence, int);
+    method public abstract android.view.textclassifier.TextClassificationResult getTextClassificationResult(java.lang.CharSequence, int, int);
+    method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+    field public static final android.view.textclassifier.TextClassifier NO_OP;
+    field public static final java.lang.String TYPE_ADDRESS = "address";
+    field public static final java.lang.String TYPE_EMAIL = "email";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+  }
+
+  public static abstract class TextClassifier.EntityType implements java.lang.annotation.Annotation {
+  }
+
+  public final class TextLanguage {
+    method public float getConfidenceScore(java.util.Locale);
+    method public int getEndIndex();
+    method public java.util.Locale getLanguage(int);
+    method public int getLanguageCount();
+    method public int getStartIndex();
+  }
+
+  public static final class TextLanguage.Builder {
+    ctor public TextLanguage.Builder(int, int);
+    method public android.view.textclassifier.TextLanguage build();
+    method public android.view.textclassifier.TextLanguage.Builder setLanguage(java.util.Locale, float);
+  }
+
+  public final class TextSelection {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public android.view.textclassifier.TextSelection build();
+    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+  }
+
+}
+
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -46425,6 +46769,7 @@
   public abstract class RenderProcessGoneDetail {
     ctor public RenderProcessGoneDetail();
     method public abstract boolean didCrash();
+    method public abstract int rendererPriorityAtExit();
   }
 
   public class ServiceWorkerClient {
@@ -46841,6 +47186,8 @@
     method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
+    method public boolean getRendererPriorityWaivedWhenNotVisible();
+    method public int getRendererRequestedPriority();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public java.lang.String getTitle();
@@ -46888,6 +47235,7 @@
     method public deprecated void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
+    method public void setRendererPriorityPolicy(int, boolean);
     method public deprecated void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
@@ -46897,6 +47245,9 @@
     method public void zoomBy(float);
     method public boolean zoomIn();
     method public boolean zoomOut();
+    field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
+    field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
+    field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
     field public static final java.lang.String SCHEME_GEO = "geo:0,0?q=";
     field public static final java.lang.String SCHEME_MAILTO = "mailto:";
     field public static final java.lang.String SCHEME_TEL = "tel:";
@@ -49202,6 +49553,10 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getAutoSizeMaxTextSize();
+    method public int getAutoSizeMinTextSize();
+    method public int getAutoSizeStepGranularity();
+    method public int getAutoSizeTextType();
     method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
@@ -49227,7 +49582,6 @@
     method public int getExtendedPaddingTop();
     method public android.text.InputFilter[] getFilters();
     method public java.lang.String getFontFeatureSettings();
-    method public java.lang.String getFontVariationSettings();
     method public boolean getFreezesText();
     method public int getGravity();
     method public int getHighlightColor();
@@ -49274,7 +49628,7 @@
     method public float getShadowRadius();
     method public final boolean getShowSoftInputOnFocus();
     method public java.lang.CharSequence getText();
-    method public android.text.TextAssistant getTextAssistant();
+    method public android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
@@ -49311,6 +49665,10 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setAutoSizeMaxTextSize(int, float);
+    method public void setAutoSizeMinTextSize(int, float);
+    method public void setAutoSizeStepGranularity(int, float);
+    method public void setAutoSizeTextType(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
@@ -49333,7 +49691,6 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFontFeatureSettings(java.lang.String);
-    method public void setFontVariationSettings(java.lang.String);
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -49387,7 +49744,7 @@
     method public final void setText(int, android.widget.TextView.BufferType);
     method public void setTextAppearance(int);
     method public deprecated void setTextAppearance(android.content.Context, int);
-    method public void setTextAssistant(android.text.TextAssistant);
+    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public void setTextColor(int);
     method public void setTextColor(android.content.res.ColorStateList);
     method public void setTextIsSelectable(boolean);
@@ -49402,8 +49759,8 @@
     method public void setTypeface(android.graphics.Typeface, int);
     method public void setTypeface(android.graphics.Typeface);
     method public void setWidth(int);
-    field public static final int AUTO_SIZE_TYPE_NONE = 0; // 0x0
-    field public static final int AUTO_SIZE_TYPE_XY = 1; // 0x1
+    field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+    field public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; // 0x1
   }
 
   public static final class TextView.BufferType extends java.lang.Enum {
@@ -50022,6 +50379,10 @@
     method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
+  public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+    ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
+  }
+
   public class PathClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public PathClassLoader(java.lang.String, java.lang.ClassLoader);
     ctor public PathClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
@@ -53120,6 +53481,133 @@
 
 }
 
+package java.lang.invoke {
+
+  public class LambdaConversionException extends java.lang.Exception {
+    ctor public LambdaConversionException();
+    ctor public LambdaConversionException(java.lang.String);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+  }
+
+  public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asFixedArity();
+    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.util.List<?>) throws java.lang.Throwable;
+    method public boolean isVarargsCollector();
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public abstract interface MethodHandleInfo {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.invoke.MethodType getMethodType();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract int getReferenceKind();
+    method public default boolean isVarArgs();
+    method public static boolean refKindIsField(int);
+    method public static boolean refKindIsValid(int);
+    method public static java.lang.String refKindName(int);
+    method public static java.lang.String referenceKindToString(int);
+    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    field public static final int REF_getField = 1; // 0x1
+    field public static final int REF_getStatic = 2; // 0x2
+    field public static final int REF_invokeInterface = 9; // 0x9
+    field public static final int REF_invokeSpecial = 7; // 0x7
+    field public static final int REF_invokeStatic = 6; // 0x6
+    field public static final int REF_invokeVirtual = 5; // 0x5
+    field public static final int REF_newInvokeSpecial = 8; // 0x8
+    field public static final int REF_putField = 3; // 0x3
+    field public static final int REF_putStatic = 4; // 0x4
+  }
+
+  public class MethodHandles {
+    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 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 filterReturnValue(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 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 java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+  }
+
+  public static final class MethodHandles.Lookup {
+    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
+    method public java.lang.Class<?> lookupClass();
+    method public int lookupModes();
+    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;
+    method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    field public static final int PACKAGE = 8; // 0x8
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+    field public static final int PUBLIC = 1; // 0x1
+  }
+
+  public final class MethodType implements java.io.Serializable {
+    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
+    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType dropParameterTypes(int, int);
+    method public java.lang.invoke.MethodType erase();
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public java.lang.invoke.MethodType generic();
+    method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
+    method public static java.lang.invoke.MethodType genericMethodType(int);
+    method public boolean hasPrimitives();
+    method public boolean hasWrappers();
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
+    method public java.lang.Class<?>[] parameterArray();
+    method public int parameterCount();
+    method public java.util.List<java.lang.Class<?>> parameterList();
+    method public java.lang.Class<?> parameterType(int);
+    method public java.lang.Class<?> returnType();
+    method public java.lang.String toMethodDescriptorString();
+    method public java.lang.invoke.MethodType unwrap();
+    method public java.lang.invoke.MethodType wrap();
+  }
+
+  public class WrongMethodTypeException extends java.lang.RuntimeException {
+    ctor public WrongMethodTypeException();
+    ctor public WrongMethodTypeException(java.lang.String);
+  }
+
+}
+
 package java.lang.ref {
 
   public class PhantomReference<T> extends java.lang.ref.Reference {
@@ -64888,14 +65376,14 @@
     method public java.util.logging.ErrorManager getErrorManager();
     method public java.util.logging.Filter getFilter();
     method public java.util.logging.Formatter getFormatter();
-    method public synchronized java.util.logging.Level getLevel();
+    method public java.util.logging.Level getLevel();
     method public boolean isLoggable(java.util.logging.LogRecord);
     method public abstract void publish(java.util.logging.LogRecord);
     method protected void reportError(java.lang.String, java.lang.Exception, int);
-    method public void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
-    method public void setErrorManager(java.util.logging.ErrorManager);
-    method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
-    method public void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
+    method public synchronized void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
+    method public synchronized void setErrorManager(java.util.logging.ErrorManager);
+    method public synchronized void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
+    method public synchronized void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
     method public synchronized void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
@@ -64922,7 +65410,7 @@
   public class LogManager {
     ctor protected LogManager();
     method public boolean addLogger(java.util.logging.Logger);
-    method public void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method public deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void checkAccess() throws java.lang.SecurityException;
     method public static java.util.logging.LogManager getLogManager();
     method public java.util.logging.Logger getLogger(java.lang.String);
@@ -64931,7 +65419,7 @@
     method public java.lang.String getProperty(java.lang.String);
     method public void readConfiguration() throws java.io.IOException, java.lang.SecurityException;
     method public void readConfiguration(java.io.InputStream) throws java.io.IOException, java.lang.SecurityException;
-    method public void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method public deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void reset() throws java.lang.SecurityException;
     field public static final java.lang.String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
   }
@@ -64968,14 +65456,18 @@
     ctor protected Logger(java.lang.String, java.lang.String);
     method public void addHandler(java.util.logging.Handler) throws java.lang.SecurityException;
     method public void config(java.lang.String);
+    method public void config(java.util.function.Supplier<java.lang.String>);
     method public void entering(java.lang.String, java.lang.String);
     method public void entering(java.lang.String, java.lang.String, java.lang.Object);
     method public void entering(java.lang.String, java.lang.String, java.lang.Object[]);
     method public void exiting(java.lang.String, java.lang.String);
     method public void exiting(java.lang.String, java.lang.String, java.lang.Object);
     method public void fine(java.lang.String);
+    method public void fine(java.util.function.Supplier<java.lang.String>);
     method public void finer(java.lang.String);
+    method public void finer(java.util.function.Supplier<java.lang.String>);
     method public void finest(java.lang.String);
+    method public void finest(java.util.function.Supplier<java.lang.String>);
     method public static java.util.logging.Logger getAnonymousLogger();
     method public static java.util.logging.Logger getAnonymousLogger(java.lang.String);
     method public java.util.logging.Filter getFilter();
@@ -64990,28 +65482,38 @@
     method public java.lang.String getResourceBundleName();
     method public boolean getUseParentHandlers();
     method public void info(java.lang.String);
+    method public void info(java.util.function.Supplier<java.lang.String>);
     method public boolean isLoggable(java.util.logging.Level);
     method public void log(java.util.logging.LogRecord);
     method public void log(java.util.logging.Level, java.lang.String);
+    method public void log(java.util.logging.Level, java.util.function.Supplier<java.lang.String>);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Object);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Object[]);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Throwable);
+    method public void log(java.util.logging.Level, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String);
+    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.util.function.Supplier<java.lang.String>);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
+    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
+    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Object...);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
+    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Throwable);
     method public void removeHandler(java.util.logging.Handler) throws java.lang.SecurityException;
     method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
     method public void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
     method public void setParent(java.util.logging.Logger);
+    method public void setResourceBundle(java.util.ResourceBundle);
     method public void setUseParentHandlers(boolean);
     method public void severe(java.lang.String);
+    method public void severe(java.util.function.Supplier<java.lang.String>);
     method public void throwing(java.lang.String, java.lang.String, java.lang.Throwable);
     method public void warning(java.lang.String);
+    method public void warning(java.util.function.Supplier<java.lang.String>);
     field public static final java.lang.String GLOBAL_LOGGER_NAME = "global";
     field public static final deprecated java.util.logging.Logger global;
   }
@@ -65032,10 +65534,10 @@
     ctor public MemoryHandler(java.util.logging.Handler, int, java.util.logging.Level);
     method public void close() throws java.lang.SecurityException;
     method public void flush();
-    method public synchronized java.util.logging.Level getPushLevel();
+    method public java.util.logging.Level getPushLevel();
     method public synchronized void publish(java.util.logging.LogRecord);
     method public synchronized void push();
-    method public void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
+    method public synchronized void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
   public class SimpleFormatter extends java.util.logging.Formatter {
diff --git a/api/system-current.txt b/api/system-current.txt
index 75b0a34..6aadccd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -138,6 +138,7 @@
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+    field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
     field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
     field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
@@ -199,6 +200,7 @@
     field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
     field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
     field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
+    field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
     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 java.lang.String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
@@ -310,6 +312,8 @@
 
   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
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -470,6 +474,7 @@
     field public static final int centerMedium = 16842959; // 0x10100cf
     field public static final int centerX = 16843170; // 0x10101a2
     field public static final int centerY = 16843171; // 0x10101a3
+    field public static final int certDigest = 16844106; // 0x101054a
     field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
     field public static final int checkMark = 16843016; // 0x1010108
     field public static final int checkMarkTint = 16843943; // 0x10104a7
@@ -864,7 +869,6 @@
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
     field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
-    field public static final int keyboardNavigationSection = 16844097; // 0x1010541
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
@@ -1014,7 +1018,6 @@
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
-    field public static final int nextSectionForward = 16844099; // 0x1010543
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -1098,6 +1101,7 @@
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int previewImage = 16843482; // 0x10102da
+    field public static final int primaryContentAlpha = 16843367; // 0x1010267
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
@@ -1161,6 +1165,7 @@
     field public static final int resizeable = 16843405; // 0x101028d
     field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
+    field public static final int restartOnConfigChanges = 16844105; // 0x1010549
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
@@ -1489,7 +1494,7 @@
     field public static final int toYDelta = 16843209; // 0x10101c9
     field public static final int toYScale = 16843205; // 0x10101c5
     field public static final int toolbarStyle = 16843946; // 0x10104aa
-    field public static final int tooltip = 16844084; // 0x1010534
+    field public static final int tooltipText = 16844084; // 0x1010534
     field public static final int top = 16843182; // 0x10101ae
     field public static final int topBright = 16842955; // 0x10100cb
     field public static final int topDark = 16842951; // 0x10100c7
@@ -1548,7 +1553,7 @@
     field public static final int viewportWidth = 16843778; // 0x1010402
     field public static final int visibility = 16842972; // 0x10100dc
     field public static final int visible = 16843156; // 0x1010194
-    field public static final int visibleToEphemeral = 16844095; // 0x101053f
+    field public static final int visibleToInstantApps = 16844095; // 0x101053f
     field public static final int vmSafeMode = 16843448; // 0x10102b8
     field public static final int voiceIcon = 16843908; // 0x1010484
     field public static final int voiceLanguage = 16843349; // 0x1010255
@@ -1925,6 +1930,7 @@
     field public static final int tabs = 16908307; // 0x1020013
     field public static final int text1 = 16908308; // 0x1020014
     field public static final int text2 = 16908309; // 0x1020015
+    field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
     field public static final int undo = 16908338; // 0x1020032
@@ -2994,8 +3000,9 @@
   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, int[]);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, 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;
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
@@ -3003,7 +3010,9 @@
     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 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);
     method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
     method public android.accounts.Account[] getAccountsByTypeForPackage(java.lang.String, java.lang.String);
@@ -3014,13 +3023,11 @@
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
-    method public int[] getRequestingUidsForType(java.lang.String);
+    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);
-    method public boolean isAccountVisible(android.accounts.Account, int);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method public boolean makeAccountVisible(android.accounts.Account, int);
     method public static deprecated android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -3028,9 +3035,9 @@
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean removeAccountExplicitly(android.accounts.Account);
-    method public boolean removeAccountVisibility(android.accounts.Account, int);
     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 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);
@@ -3069,7 +3076,14 @@
     field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
-    field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+    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 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
+    field public static final int VISIBILITY_USER_MANAGED_VISIBLE = 2; // 0x2
+    field public static final int VISIBILITY_VISIBLE = 1; // 0x1
   }
 
   public abstract interface AccountManagerCallback<V> {
@@ -3609,8 +3623,7 @@
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void enterPictureInPictureMode();
-    method public void enterPictureInPictureMode(float);
-    method public void enterPictureInPictureModeOnMoveToBackground(boolean);
+    method public boolean enterPictureInPictureMode(android.app.PictureInPictureArgs);
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3643,7 +3656,6 @@
     method public int getRequestedOrientation();
     method public final android.view.SearchEvent getSearchEvent();
     method public int getTaskId();
-    method public android.text.TextAssistant getTextAssistant();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
     method public android.app.VoiceInteractor getVoiceInteractor();
@@ -3785,8 +3797,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
-    method public void setPictureInPictureActions(java.util.List<android.app.RemoteAction>);
-    method public void setPictureInPictureAspectRatio(float);
+    method public void setPictureInPictureArgs(android.app.PictureInPictureArgs);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3796,7 +3807,6 @@
     method public final void setResult(int, android.content.Intent);
     method public final deprecated void setSecondaryProgress(int);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
-    method public void setTextAssistant(android.text.TextAssistant);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public deprecated void setTitleColor(int);
@@ -4748,6 +4758,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -4983,11 +4994,13 @@
   public static class Instrumentation.ActivityMonitor {
     ctor public Instrumentation.ActivityMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     ctor public Instrumentation.ActivityMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    ctor public Instrumentation.ActivityMonitor();
     method public final android.content.IntentFilter getFilter();
     method public final int getHits();
     method public final android.app.Activity getLastActivity();
     method public final android.app.Instrumentation.ActivityResult getResult();
     method public final boolean isBlocking();
+    method public android.app.Instrumentation.ActivityResult onMatchIntent(android.content.Intent);
     method public final android.app.Activity waitForActivity();
     method public final android.app.Activity waitForActivityWithTimeout(long);
   }
@@ -5183,6 +5196,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5268,6 +5282,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
+    method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
@@ -5484,6 +5499,19 @@
     field protected android.app.Notification.Builder mBuilder;
   }
 
+  public static final class Notification.TvExtender implements android.app.Notification.Extender {
+    ctor public Notification.TvExtender();
+    ctor public Notification.TvExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public java.lang.String getChannel();
+    method public android.app.PendingIntent getContentIntent();
+    method public android.app.PendingIntent getDeleteIntent();
+    method public boolean isAvailableOnTv();
+    method public android.app.Notification.TvExtender setChannel(java.lang.String);
+    method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
+    method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
+  }
+
   public static final class Notification.WearableExtender implements android.app.Notification.Extender {
     ctor public Notification.WearableExtender();
     ctor public Notification.WearableExtender(android.app.Notification);
@@ -5558,10 +5586,11 @@
     method public android.net.Uri getSound();
     method public int getUserLockedFields();
     method public long[] getVibrationPattern();
-    method public boolean isAllowed();
+    method public boolean isDeleted();
     method public void lockFields(int);
     method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
     method public void setBypassDnd(boolean);
+    method public void setDeleted(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
     method public void setLockscreenVisibility(int);
@@ -5609,6 +5638,7 @@
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
+    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
@@ -5694,6 +5724,17 @@
     method public abstract void onSendFinished(android.app.PendingIntent, android.content.Intent, int, java.lang.String, android.os.Bundle);
   }
 
+  public final class PictureInPictureArgs implements android.os.Parcelable {
+    ctor public PictureInPictureArgs();
+    ctor public PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
+    method public android.app.PictureInPictureArgs clone();
+    method public int describeContents();
+    method public void setActions(java.util.List<android.app.RemoteAction>);
+    method public void setAspectRatio(float);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
+  }
+
   public class Presentation extends android.app.Dialog {
     ctor public Presentation(android.content.Context, android.view.Display);
     ctor public Presentation(android.content.Context, android.view.Display, int);
@@ -5730,6 +5771,18 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
+    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+    method public int describeContents();
+    method public android.app.PendingIntent getUserAction();
+    method public java.lang.CharSequence getUserActionTitle();
+    method public java.lang.CharSequence getUserMessage();
+    method public void showAsDialog(android.app.Activity);
+    method public void showAsNotification(android.content.Context);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
+  }
+
   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);
     method public android.app.RemoteAction clone();
@@ -5747,14 +5800,18 @@
   }
 
   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);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5766,6 +5823,7 @@
     method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
@@ -6292,6 +6350,7 @@
     method public int getPasswordMinimumSymbols(android.content.ComponentName);
     method public int getPasswordMinimumUpperCase(android.content.ComponentName);
     method public int getPasswordQuality(android.content.ComponentName);
+    method public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(android.content.ComponentName);
     method public int getPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int getPermissionPolicy(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
@@ -6318,6 +6377,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isBackupServiceEnabled(android.content.ComponentName);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceManaged();
     method public boolean isDeviceOwnerApp(java.lang.String);
@@ -6335,6 +6395,8 @@
     method public void lockNow();
     method public void lockNow(int);
     method public void notifyPendingSystemUpdate(long);
+    method public void notifyPendingSystemUpdate(long, boolean);
+    method public boolean packageHasActiveAdmins(java.lang.String);
     method public void reboot(android.content.ComponentName);
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -6353,6 +6415,7 @@
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
+    method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
@@ -6537,6 +6600,17 @@
     field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
   }
 
+  public final class SystemUpdateInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getReceivedTime();
+    method public int getSecurityPatchState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdateInfo> CREATOR;
+    field public static final int SECURITY_PATCH_STATE_FALSE = 1; // 0x1
+    field public static final int SECURITY_PATCH_STATE_TRUE = 2; // 0x2
+    field public static final int SECURITY_PATCH_STATE_UNKNOWN = 0; // 0x0
+  }
+
   public class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6710,6 +6784,7 @@
     method public boolean isBackupEnabled();
     method public java.lang.String[] listAllTransports();
     method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
+    method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver, int);
     method public int requestRestore(android.app.backup.RestoreObserver);
     method public java.lang.String selectBackupTransport(java.lang.String);
     method public void setAutoRestore(boolean);
@@ -6720,6 +6795,8 @@
     field public static final int ERROR_TRANSPORT_ABORTED = -1000; // 0xfffffc18
     field public static final int ERROR_TRANSPORT_PACKAGE_REJECTED = -1002; // 0xfffffc16
     field public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13
+    field public static final int FLAG_NON_INCREMENTAL_BACKUP = 1; // 0x1
+    field public static final java.lang.String PACKAGE_MANAGER_SENTINEL = "@pm@";
     field public static final int SUCCESS = 0; // 0x0
   }
 
@@ -8261,6 +8338,7 @@
     ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
     ctor public ClipData(android.content.ClipData);
     method public void addItem(android.content.ClipData.Item);
+    method public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
     method public int describeContents();
     method public android.content.ClipDescription getDescription();
     method public android.content.ClipData.Item getItemAt(int);
@@ -8787,6 +8865,7 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
@@ -9381,10 +9460,10 @@
     field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
@@ -9898,6 +9977,7 @@
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
     method public final int getThemeResource();
+    field public static final int CONFIG_COLORIMETRY = 16384; // 0x4000
     field public static final int CONFIG_DENSITY = 4096; // 0x1000
     field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
     field public static final int CONFIG_KEYBOARD = 16; // 0x10
@@ -10174,6 +10254,15 @@
     field public java.lang.String targetPackage;
   }
 
+  public final class IntentFilterVerificationInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.util.Set<java.lang.String> getDomains();
+    method public java.lang.String getPackageName();
+    method public int getStatus();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
+  }
+
   public class LabeledIntent extends android.content.Intent {
     ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
     ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -10203,7 +10292,10 @@
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
+    method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
@@ -10238,7 +10330,7 @@
     method public boolean accept(android.os.Bundle);
     method public boolean accept();
     method public int describeContents();
-    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo();
+    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo(android.content.Context);
     method public int getRequestType();
     method public android.content.pm.ShortcutInfo getShortcutInfo();
     method public boolean isValid();
@@ -10307,6 +10399,7 @@
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
     method public void uninstall(java.lang.String, android.content.IntentSender);
+    method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender);
     method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void updateSessionAppIcon(int, android.graphics.Bitmap);
     method public void updateSessionAppLabel(int, java.lang.CharSequence);
@@ -10435,6 +10528,7 @@
     method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
     method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
     method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
     method public abstract android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -10447,12 +10541,15 @@
     method public abstract android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int getComponentEnabledSetting(android.content.ComponentName);
     method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
     method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
+    method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
@@ -10460,6 +10557,7 @@
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInstaller getPackageInstaller();
     method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] getPackagesForUid(int);
@@ -10475,6 +10573,7 @@
     method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -10506,7 +10605,9 @@
     method public abstract void setApplicationCategoryHint(java.lang.String, int);
     method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
     method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
     method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
+    method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
     method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
     method public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
     method public abstract void verifyPendingInstall(int, int);
@@ -10585,6 +10686,7 @@
     field public static final java.lang.String FEATURE_SIP = "android.software.sip";
     field public static final java.lang.String FEATURE_SIP_VOIP = "android.software.sip.voip";
     field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
+    field public static final java.lang.String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
     field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
     field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
     field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
@@ -10666,6 +10768,11 @@
     field public static final int INSTALL_REASON_POLICY = 1; // 0x1
     field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
     field public static final int INSTALL_SUCCEEDED = 1; // 0x1
+    field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2; // 0x2
+    field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4; // 0x4
+    field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK = 1; // 0x1
+    field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3; // 0x3
+    field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED = 0; // 0x0
     field public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; // 0xffffffff
     field public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
     field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
@@ -10689,6 +10796,7 @@
     field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
     field public static final int VERIFICATION_ALLOW = 1; // 0x1
     field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
+    field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
   }
 
   public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -10837,6 +10945,20 @@
     field public java.lang.String permission;
   }
 
+  public final class SharedLibraryInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.pm.VersionedPackage getDeclaringPackage();
+    method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
+    method public java.lang.String getName();
+    method public int getVersion();
+    method public boolean isBuiltin();
+    method public boolean isDynamic();
+    method public boolean isStatic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR;
+    field public static final int VERSION_UNDEFINED = -1; // 0xffffffff
+  }
+
   public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getActivity();
@@ -10880,6 +11002,7 @@
 
   public class ShortcutManager {
     method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
     method public void disableShortcuts(java.util.List<java.lang.String>);
     method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
     method public void enableShortcuts(java.util.List<java.lang.String>);
@@ -10911,6 +11034,15 @@
     field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR;
   }
 
+  public final class VersionedPackage implements android.os.Parcelable {
+    ctor public VersionedPackage(java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public long getVersionCode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR;
+  }
+
 }
 
 package android.content.pm.permission {
@@ -11010,7 +11142,9 @@
     method public int getLayoutDirection();
     method public android.os.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
+    method public boolean isScreenHdr();
     method public boolean isScreenRound();
+    method public boolean isScreenWideColorGamut();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
@@ -11020,6 +11154,16 @@
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int COLORIMETRY_HDR_MASK = 12; // 0xc
+    field public static final int COLORIMETRY_HDR_NO = 4; // 0x4
+    field public static final int COLORIMETRY_HDR_SHIFT = 2; // 0x2
+    field public static final int COLORIMETRY_HDR_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_HDR_YES = 8; // 0x8
+    field public static final int COLORIMETRY_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 1; // 0x1
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 2; // 0x2
     field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
     field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
     field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
@@ -11085,6 +11229,7 @@
     field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
     field public static final int UI_MODE_TYPE_VR_HEADSET = 7; // 0x7
     field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
+    field public int colorimetry;
     field public int densityDpi;
     field public float fontScale;
     field public int hardKeyboardHidden;
@@ -11139,6 +11284,7 @@
     method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
+    method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
     method public float getFraction(int, int, int);
     method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
     method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;
@@ -12625,15 +12771,57 @@
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
     method public static void RGBToHSV(int, int, int, float[]);
+    method public float alpha();
+    method public static float alpha(long);
     method public static int alpha(int);
     method public static int argb(int, int, int, int);
+    method public static int argb(float, float, float, float);
+    method public float blue();
+    method public static float blue(long);
     method public static int blue(int);
+    method public static android.graphics.ColorSpace colorSpace(long);
     method public static void colorToHSV(int, float[]);
+    method public android.graphics.Color convert(android.graphics.ColorSpace);
+    method public static long convert(int, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace.Connector);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
+    method public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(int);
+    method public int getComponentCount();
+    method public float[] getComponents();
+    method public android.graphics.ColorSpace.Model getModel();
+    method public float green();
+    method public static float green(long);
     method public static int green(int);
+    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public boolean isSrgb();
+    method public static boolean isSrgb(long);
+    method public boolean isWideGamut();
+    method public static boolean isWideGamut(long);
+    method public float luminance();
+    method public static float luminance(long);
     method public static float luminance(int);
+    method public long pack();
+    method public static long pack(int);
+    method public static long pack(float, float, float);
+    method public static long pack(float, float, float, float);
+    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
     method public static int parseColor(java.lang.String);
+    method public float red();
+    method public static float red(long);
     method public static int red(int);
     method public static int rgb(int, int, int);
+    method public static int rgb(float, float, float);
+    method public int toArgb();
+    method public static int toArgb(long);
+    method public static android.graphics.Color valueOf(int);
+    method public static android.graphics.Color valueOf(long);
+    method public static android.graphics.Color valueOf(float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
+    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
     field public static final int BLACK = -16777216; // 0xff000000
     field public static final int BLUE = -16776961; // 0xff0000ff
     field public static final int CYAN = -16711681; // 0xff00ffff
@@ -12705,7 +12893,7 @@
     field public static final float[] ILLUMINANT_D65;
     field public static final float[] ILLUMINANT_D75;
     field public static final float[] ILLUMINANT_E;
-    field public static final int MAX_ID = 64; // 0x40
+    field public static final int MAX_ID = 63; // 0x3f
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
@@ -13028,7 +13216,6 @@
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
     method public float getFontSpacing();
-    method public java.lang.String getFontVariationSettings();
     method public int getHinting();
     method public float getLetterSpacing();
     method public android.graphics.MaskFilter getMaskFilter();
@@ -13086,7 +13273,6 @@
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(java.lang.String);
-    method public void setFontVariationSettings(java.lang.String);
     method public void setHinting(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
@@ -14485,6 +14671,37 @@
     method public float getZ();
   }
 
+  public final class HardwareBuffer implements android.os.Parcelable {
+    method public static android.hardware.HardwareBuffer create(int, int, int, int, long);
+    method public int describeContents();
+    method public void destroy();
+    method public int getFormat();
+    method public int getHeight();
+    method public int getLayers();
+    method public long getUsage();
+    method public int getWidth();
+    method public boolean isDestroyed();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
+    field public static final int RGBA_8888 = 1; // 0x1
+    field public static final int RGBA_FP16 = 5; // 0x5
+    field public static final int RGBX_8888 = 2; // 0x2
+    field public static final int RGB_565 = 4; // 0x4
+    field public static final int RGB_888 = 3; // 0x3
+    field public static final long USAGE0_CPU_READ = 2L; // 0x2L
+    field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L
+    field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L
+    field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L
+    field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L
+    field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L
+    field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L
+    field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L
+    field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L
+    field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L
+    field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L
+    field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L
+  }
+
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
@@ -20912,6 +21129,7 @@
     method public double getAccumulatedDeltaRangeMeters();
     method public int getAccumulatedDeltaRangeState();
     method public double getAccumulatedDeltaRangeUncertaintyMeters();
+    method public double getAutomaticGainControlLevelInDb();
     method public long getCarrierCycles();
     method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
@@ -20927,6 +21145,7 @@
     method public int getState();
     method public int getSvid();
     method public double getTimeOffsetNanos();
+    method public boolean hasAutomaticGainControlLevelInDb();
     method public boolean hasCarrierCycles();
     method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
@@ -20950,11 +21169,13 @@
     field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
     field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
     field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
     field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
     field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
     field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
     field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
     field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
     field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
@@ -21011,12 +21232,14 @@
 
   public final class GnssStatus {
     method public float getAzimuthDegrees(int);
+    method public float getCarrierFrequencyHz(int);
     method public float getCn0DbHz(int);
     method public int getConstellationType(int);
     method public float getElevationDegrees(int);
     method public int getSatelliteCount();
     method public int getSvid(int);
     method public boolean hasAlmanacData(int);
+    method public boolean hasCarrierFrequency(int);
     method public boolean hasEphemerisData(int);
     method public boolean usedInFix(int);
     field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
@@ -21302,29 +21525,39 @@
     method public float getAccuracy();
     method public double getAltitude();
     method public float getBearing();
+    method public float getBearingAccuracyDegrees();
     method public long getElapsedRealtimeNanos();
     method public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
     method public java.lang.String getProvider();
     method public float getSpeed();
+    method public float getSpeedAccuracyMetersPerSecond();
     method public long getTime();
+    method public float getVerticalAccuracyMeters();
     method public boolean hasAccuracy();
     method public boolean hasAltitude();
     method public boolean hasBearing();
+    method public boolean hasBearingAccuracy();
     method public boolean hasSpeed();
+    method public boolean hasSpeedAccuracy();
+    method public boolean hasVerticalAccuracy();
     method public boolean isComplete();
     method public boolean isFromMockProvider();
     method public void makeComplete();
     method public void removeAccuracy();
     method public void removeAltitude();
     method public void removeBearing();
+    method public void removeBearingAccuracy();
     method public void removeSpeed();
+    method public void removeSpeedAccuracy();
+    method public void removeVerticalAccuracy();
     method public void reset();
     method public void set(android.location.Location);
     method public void setAccuracy(float);
     method public void setAltitude(double);
     method public void setBearing(float);
+    method public void setBearingAccuracyDegrees(float);
     method public void setElapsedRealtimeNanos(long);
     method public void setExtras(android.os.Bundle);
     method public void setIsFromMockProvider(boolean);
@@ -21332,7 +21565,9 @@
     method public void setLongitude(double);
     method public void setProvider(java.lang.String);
     method public void setSpeed(float);
+    method public void setSpeedAccuracyMetersPerSecond(float);
     method public void setTime(long);
+    method public void setVerticalAccuracyMeters(float);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
     field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -21854,6 +22089,7 @@
     method public int getClientPid();
     method public int getClientUid();
     method public int getPlayerInterfaceId();
+    method public android.media.PlayerProxy getPlayerProxy();
     method public int getPlayerState();
     method public int getPlayerType();
     method public void writeToParcel(android.os.Parcel, int);
@@ -23393,6 +23629,8 @@
     method public void setLocation(float, float);
     method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
     method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
+    method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalStateException;
+    method public void setNextOutputFile(java.lang.String) throws java.io.IOException, java.lang.IllegalStateException;
     method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener);
     method public void setOnInfoListener(android.media.MediaRecorder.OnInfoListener);
     method public void setOrientationHint(int);
@@ -23411,7 +23649,9 @@
     field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
+    field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802; // 0x322
     field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801; // 0x321
+    field public static final int MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803; // 0x323
     field public static final int MEDIA_RECORDER_INFO_UNKNOWN = 1; // 0x1
   }
 
@@ -23682,6 +23922,13 @@
     field public static final android.os.Parcelable.Creator<android.media.PlaybackParams> CREATOR;
   }
 
+  public class PlayerProxy {
+    method public void pause() throws java.lang.IllegalStateException;
+    method public void setVolume(float) throws java.lang.IllegalStateException;
+    method public void start() throws java.lang.IllegalStateException;
+    method public void stop() throws java.lang.IllegalStateException;
+  }
+
   public final class Rating implements android.os.Parcelable {
     method public int describeContents();
     method public float getPercentRating();
@@ -26241,9 +26488,14 @@
   public final class RecommendationRequest implements android.os.Parcelable {
     ctor protected RecommendationRequest(android.os.Parcel);
     method public int describeContents();
-    method public android.net.wifi.WifiConfiguration getCurrentSelectedConfig();
-    method public android.net.NetworkCapabilities getRequiredCapabilities();
+    method public android.net.wifi.WifiConfiguration[] getConnectableConfigs();
+    method public android.net.wifi.WifiConfiguration getConnectedConfig();
+    method public android.net.wifi.WifiConfiguration getDefaultWifiConfig();
+    method public int getLastSelectedNetworkId();
+    method public long getLastSelectedNetworkTimestamp();
     method public android.net.wifi.ScanResult[] getScanResults();
+    method public void setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
+    method public void setConnectedConfig(android.net.wifi.WifiConfiguration);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
   }
@@ -26251,8 +26503,10 @@
   public static final class RecommendationRequest.Builder {
     ctor public RecommendationRequest.Builder();
     method public android.net.RecommendationRequest build();
-    method public android.net.RecommendationRequest.Builder setCurrentRecommendedWifiConfig(android.net.wifi.WifiConfiguration);
-    method public android.net.RecommendationRequest.Builder setNetworkCapabilities(android.net.NetworkCapabilities);
+    method public android.net.RecommendationRequest.Builder setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
+    method public android.net.RecommendationRequest.Builder setConnectedWifiConfig(android.net.wifi.WifiConfiguration);
+    method public android.net.RecommendationRequest.Builder setDefaultWifiConfig(android.net.wifi.WifiConfiguration);
+    method public android.net.RecommendationRequest.Builder setLastSelectedNetwork(int, long);
     method public android.net.RecommendationRequest.Builder setScanResults(android.net.wifi.ScanResult[]);
   }
 
@@ -26344,6 +26598,7 @@
     ctor public TrafficStats();
     method public static void clearThreadStatsTag();
     method public static void clearThreadStatsUid();
+    method public static int getAndSetThreadStatsTag(int);
     method public static long getMobileRxBytes();
     method public static long getMobileRxPackets();
     method public static long getMobileTxBytes();
@@ -27350,6 +27605,7 @@
     method public int describeContents();
     method public android.net.ProxyInfo getHttpProxy();
     method public boolean hasNoInternetAccess();
+    method public boolean isEphemeral();
     method public boolean isNoInternetAccessExpected();
     method public boolean isPasspoint();
     method public void setHttpProxy(android.net.ProxyInfo);
@@ -32448,6 +32704,15 @@
     field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
   }
 
+  public abstract class ProxyFileDescriptorCallback {
+    ctor public ProxyFileDescriptorCallback();
+    method public void onFsync() throws android.system.ErrnoException;
+    method public long onGetSize() throws android.system.ErrnoException;
+    method public int onRead(long, int, byte[]) throws android.system.ErrnoException;
+    method public abstract void onRelease();
+    method public int onWrite(long, int, byte[]) throws android.system.ErrnoException;
+  }
+
   public class RecoverySystem {
     method public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
@@ -32581,6 +32846,7 @@
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
+    method public android.os.StrictMode.VmPolicy.Builder detectUntaggedSockets();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
@@ -32695,7 +32961,8 @@
     method public android.os.UserHandle getUserForSerialNumber(long);
     method public java.lang.String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
-    method public int getUserRestrictionSource(java.lang.String, android.os.UserHandle);
+    method public deprecated int getUserRestrictionSource(java.lang.String, android.os.UserHandle);
+    method public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(java.lang.String, android.os.UserHandle);
     method public android.os.Bundle getUserRestrictions();
     method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(java.lang.String);
@@ -32761,6 +33028,14 @@
     field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
+  public static final class UserManager.EnforcingUser implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.UserHandle getUserHandle();
+    method public int getUserRestrictionSource();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.UserManager.EnforcingUser> CREATOR;
+  }
+
   public static abstract class UserManager.UserRestrictionSource implements java.lang.annotation.Annotation {
   }
 
@@ -32944,13 +33219,22 @@
   }
 
   public class StorageManager {
+    method public long getCacheQuotaBytes();
+    method public long getCacheSizeBytes();
+    method public long getExternalCacheQuotaBytes();
+    method public long getExternalCacheSizeBytes();
     method public java.lang.String getMountedObbPath(java.lang.String);
     method public android.os.storage.StorageVolume getPrimaryStorageVolume();
     method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
     method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method public boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
+    method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
     method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+    method public void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
+    method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
     field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
   }
@@ -35087,7 +35371,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -35227,8 +35511,10 @@
   public static final class ContactsContract.ProviderStatus {
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
+    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -35374,6 +35660,7 @@
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -35418,6 +35705,7 @@
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+    field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -35451,6 +35739,7 @@
     ctor public DocumentsProvider();
     method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
     method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
@@ -36042,6 +36331,7 @@
     field public static final java.lang.String BOOT_COUNT = "boot_count";
     field public static final java.lang.String CONTACT_METADATA_SYNC_ENABLED = "contact_metadata_sync_enabled";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String CURATE_SAVED_OPEN_NETWORKS = "curate_saved_open_networks";
     field public static final java.lang.String DATA_ROAMING = "data_roaming";
     field public static final java.lang.String DEBUG_APP = "debug_app";
     field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
@@ -38017,6 +38307,7 @@
     field public static final int PURPOSE_ENCRYPT = 1; // 0x1
     field public static final int PURPOSE_SIGN = 4; // 0x4
     field public static final int PURPOSE_VERIFY = 8; // 0x8
+    field public static final int PURPOSE_WRAP_KEY = 16; // 0x10
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
   }
@@ -38076,6 +38367,7 @@
     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 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 {
@@ -38281,7 +38573,6 @@
     field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
     field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -38605,6 +38896,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public boolean onConfigure(java.util.List<android.os.PersistableBundle>);
     method public void onDeviceLocked();
+    method public void onDeviceUnlockLockout(long);
     method public void onDeviceUnlocked();
     method public void onTrustTimeout();
     method public void onUnlockAttempt(boolean);
@@ -40038,6 +40330,7 @@
     method public void onReject();
     method public void onReject(java.lang.String);
     method public void onSeparate();
+    method public void onShowIncomingCallUi();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
@@ -40049,6 +40342,7 @@
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
+    method public final void setAudioRoute(int);
     method public final void setCallerDisplayName(java.lang.String, int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
@@ -40097,6 +40391,7 @@
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
+    field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -40164,7 +40459,9 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -40401,6 +40698,7 @@
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
@@ -40639,6 +40937,8 @@
     method public boolean handleMmi(java.lang.String);
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
+    method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
+    method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
     method public boolean isRinging();
     method public boolean isTtySupported();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
@@ -40651,7 +40951,7 @@
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT";
     field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
-    field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
+    field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
     field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
     field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
@@ -40761,7 +41061,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -40853,9 +41154,13 @@
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -41381,6 +41686,7 @@
     method public void enableVideoCalling(boolean);
     method public boolean endCall();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+    method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method public int getCallState();
     method public android.os.PersistableBundle getCarrierConfig();
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
@@ -41456,6 +41762,7 @@
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
     method public void sendUssdRequest(java.lang.String, int, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
+    method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method public void setDataEnabled(boolean);
     method public void setDataEnabled(int, boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
@@ -42147,6 +42454,7 @@
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public android.content.ComponentName startService(android.content.Intent);
+    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
     method public boolean stopService(android.content.Intent);
     method public void unbindService(android.content.ServiceConnection);
     method public void unregisterReceiver(android.content.BroadcastReceiver);
@@ -42237,18 +42545,22 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
+    method public int getIntentVerificationStatusAsUser(java.lang.String, int);
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
     method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] getPackagesForUid(int);
@@ -42264,6 +42576,7 @@
     method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
     method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public java.lang.String[] getSystemSharedLibraryNames();
     method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -42294,7 +42607,9 @@
     method public void setApplicationCategoryHint(java.lang.String, int);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
+    method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
     method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
     method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
     method public void verifyPendingInstall(int, int);
@@ -42498,6 +42813,65 @@
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
+  public final class FontConfig implements android.os.Parcelable {
+    ctor public FontConfig();
+    ctor public FontConfig(android.text.FontConfig);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method public java.util.List<android.text.FontConfig.Family> getFamilies();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
+  }
+
+  public static final class FontConfig.Alias implements android.os.Parcelable {
+    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getName();
+    method public java.lang.String getToName();
+    method public int getWeight();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
+  }
+
+  public static final class FontConfig.Axis implements android.os.Parcelable {
+    ctor public FontConfig.Axis(int, float);
+    method public int describeContents();
+    method public float getStyleValue();
+    method public int getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
+  }
+
+  public static final class FontConfig.Family implements android.os.Parcelable {
+    ctor public FontConfig.Family(java.lang.String, java.util.List<android.text.FontConfig.Font>, java.lang.String, java.lang.String);
+    ctor public FontConfig.Family(android.text.FontConfig.Family);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Font> getFonts();
+    method public java.lang.String getLanguage();
+    method public java.lang.String getName();
+    method public java.lang.String getVariant();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
+  }
+
+  public static final class FontConfig.Font implements android.os.Parcelable {
+    ctor public FontConfig.Font(java.lang.String, int, java.util.List<android.text.FontConfig.Axis>, int, boolean);
+    ctor public FontConfig.Font(android.text.FontConfig.Font);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Axis> getAxes();
+    method public android.os.ParcelFileDescriptor getFd();
+    method public java.lang.String getFontName();
+    method public int getTtcIndex();
+    method public int getWeight();
+    method public boolean isItalic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
+  }
+
+  public final class FontManager {
+    method public android.text.FontConfig getSystemFonts();
+  }
+
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
@@ -42853,22 +43227,6 @@
     method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
   }
 
-  public abstract interface TextAssistant {
-    method public abstract void addLinks(android.text.Spannable, int);
-    method public abstract android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
-  public class TextClassification {
-    ctor public TextClassification();
-    method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence();
-  }
-
-  public final class TextClassificationManager implements android.text.TextAssistant {
-    method public void addLinks(android.text.Spannable, int);
-    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
-    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -42884,13 +43242,6 @@
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
-  public final class TextLanguage {
-    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public int getEndIndex();
-    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
-    method public int getStartIndex();
-  }
-
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -42903,13 +43254,6 @@
     field public int linkColor;
   }
 
-  public class TextSelection {
-    ctor public TextSelection();
-    method public int getSelectionEndIndex();
-    method public int getSelectionStartIndex();
-    method public android.text.TextClassification getTextClassification();
-  }
-
   public class TextUtils {
     method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String);
     method public static java.lang.CharSequence concat(java.lang.CharSequence...);
@@ -44463,6 +44807,7 @@
     method public static int getTagCode(java.lang.String);
     method public static java.lang.String getTagName(int);
     method public static void readEvents(int[], java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
+    method public static void readEventsOnWrapping(int[], long, java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
     method public static int writeEvent(int, int);
     method public static int writeEvent(int, long);
     method public static int writeEvent(int, float);
@@ -45163,7 +45508,9 @@
     method public android.view.Display.Mode[] getSupportedModes();
     method public deprecated float[] getSupportedRefreshRates();
     method public deprecated int getWidth();
+    method public boolean isHdr();
     method public boolean isValid();
+    method public boolean isWideColorGamut();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
     field public static final int FLAG_PRESENTATION = 8; // 0x8
     field public static final int FLAG_PRIVATE = 4; // 0x4
@@ -45232,7 +45579,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
-    method public android.view.View findNextKeyboardNavigationGroup(int, android.view.View, android.view.View, int);
+    method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -46017,7 +46364,7 @@
     method public abstract android.view.SubMenu getSubMenu();
     method public abstract java.lang.CharSequence getTitle();
     method public abstract java.lang.CharSequence getTitleCondensed();
-    method public default java.lang.CharSequence getTooltip();
+    method public default java.lang.CharSequence getTooltipText();
     method public abstract boolean hasSubMenu();
     method public abstract boolean isActionViewExpanded();
     method public abstract boolean isCheckable();
@@ -46044,7 +46391,7 @@
     method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
     method public abstract android.view.MenuItem setTitle(int);
     method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
-    method public default android.view.MenuItem setTooltip(java.lang.CharSequence);
+    method public default android.view.MenuItem setTooltipText(java.lang.CharSequence);
     method public abstract android.view.MenuItem setVisible(boolean);
     field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
@@ -46530,7 +46877,7 @@
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     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 addKeyboardNavigationGroups(int, java.util.Collection<android.view.View>, int);
+    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -46694,7 +47041,6 @@
     method public int getNextFocusLeftId();
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
-    method public int getNextSectionForwardId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method public int getOverScrollMode();
@@ -46738,7 +47084,8 @@
     method public java.lang.Object getTag(int);
     method public int getTextAlignment();
     method public int getTextDirection();
-    method public final java.lang.CharSequence getTooltip();
+    method public final deprecated java.lang.CharSequence getTooltip();
+    method public final java.lang.CharSequence getTooltipText();
     method public final int getTop();
     method protected float getTopFadingEdgeStrength();
     method protected int getTopPaddingOffset();
@@ -46799,7 +47146,6 @@
     method public boolean isInLayout();
     method public boolean isInTouchMode();
     method public final boolean isKeyboardNavigationCluster();
-    method public final boolean isKeyboardNavigationSection();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
@@ -46822,7 +47168,7 @@
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
-    method public android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
@@ -46972,7 +47318,6 @@
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
     method public void setKeyboardNavigationCluster(boolean);
-    method public void setKeyboardNavigationSection(boolean);
     method public void setLabelFor(int);
     method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
@@ -46990,7 +47335,6 @@
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
-    method public void setNextSectionForwardId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -47039,7 +47383,8 @@
     method public void setTag(int, java.lang.Object);
     method public void setTextAlignment(int);
     method public void setTextDirection(int);
-    method public final void setTooltip(java.lang.CharSequence);
+    method public final deprecated void setTooltip(java.lang.CharSequence);
+    method public final void setTooltipText(java.lang.CharSequence);
     method public final void setTop(int);
     method public void setTouchDelegate(android.view.TouchDelegate);
     method public final void setTransitionName(java.lang.String);
@@ -47116,8 +47461,6 @@
     field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
     field public static final int INVISIBLE = 4; // 0x4
     field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
-    field public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; // 0x1
-    field public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; // 0x2
     field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
     field public static final int LAYER_TYPE_NONE = 0; // 0x0
     field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
@@ -47636,7 +47979,7 @@
     method public abstract boolean isLayoutRequested();
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
-    method public abstract android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract boolean onNestedPreFling(android.view.View, float, float);
@@ -49426,6 +49769,83 @@
 
 }
 
+package android.view.textclassifier {
+
+  public abstract interface LinksInfo {
+    method public abstract boolean apply(java.lang.CharSequence);
+  }
+
+  public final class TextClassificationManager {
+    method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.view.textclassifier.TextClassifier getDefaultTextClassifier();
+  }
+
+  public final class TextClassificationResult {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public android.view.View.OnClickListener getOnClickListener();
+    method public java.lang.String getText();
+  }
+
+  public static final class TextClassificationResult.Builder {
+    ctor public TextClassificationResult.Builder();
+    method public android.view.textclassifier.TextClassificationResult build();
+    method public android.view.textclassifier.TextClassificationResult.Builder setEntityType(java.lang.String, float);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIntent(android.content.Intent);
+    method public android.view.textclassifier.TextClassificationResult.Builder setLabel(java.lang.String);
+    method public android.view.textclassifier.TextClassificationResult.Builder setOnClickListener(android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassificationResult.Builder setText(java.lang.String);
+  }
+
+  public abstract interface TextClassifier {
+    method public abstract android.view.textclassifier.LinksInfo getLinks(java.lang.CharSequence, int);
+    method public abstract android.view.textclassifier.TextClassificationResult getTextClassificationResult(java.lang.CharSequence, int, int);
+    method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+    field public static final android.view.textclassifier.TextClassifier NO_OP;
+    field public static final java.lang.String TYPE_ADDRESS = "address";
+    field public static final java.lang.String TYPE_EMAIL = "email";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+  }
+
+  public static abstract class TextClassifier.EntityType implements java.lang.annotation.Annotation {
+  }
+
+  public final class TextLanguage {
+    method public float getConfidenceScore(java.util.Locale);
+    method public int getEndIndex();
+    method public java.util.Locale getLanguage(int);
+    method public int getLanguageCount();
+    method public int getStartIndex();
+  }
+
+  public static final class TextLanguage.Builder {
+    ctor public TextLanguage.Builder(int, int);
+    method public android.view.textclassifier.TextLanguage build();
+    method public android.view.textclassifier.TextLanguage.Builder setLanguage(java.util.Locale, float);
+  }
+
+  public final class TextSelection {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public android.view.textclassifier.TextSelection build();
+    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+  }
+
+}
+
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -49710,6 +50130,7 @@
   public abstract class RenderProcessGoneDetail {
     ctor public RenderProcessGoneDetail();
     method public abstract boolean didCrash();
+    method public abstract int rendererPriorityAtExit();
   }
 
   public class ServiceWorkerClient {
@@ -50165,6 +50586,8 @@
     method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
+    method public boolean getRendererPriorityWaivedWhenNotVisible();
+    method public int getRendererRequestedPriority();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public java.lang.String getTitle();
@@ -50213,6 +50636,7 @@
     method public deprecated void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
+    method public void setRendererPriorityPolicy(int, boolean);
     method public deprecated void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
@@ -50223,6 +50647,9 @@
     method public boolean zoomIn();
     method public boolean zoomOut();
     field public static final java.lang.String DATA_REDUCTION_PROXY_SETTING_CHANGED = "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
+    field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
+    field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
+    field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
     field public static final java.lang.String SCHEME_GEO = "geo:0,0?q=";
     field public static final java.lang.String SCHEME_MAILTO = "mailto:";
     field public static final java.lang.String SCHEME_TEL = "tel:";
@@ -50356,6 +50783,7 @@
     method public java.lang.String getErrorString(android.content.Context, int);
     method public int getPackageId(android.content.res.Resources, java.lang.String);
     method public void invokeDrawGlFunctor(android.view.View, long, boolean);
+    method public boolean isMultiProcessEnabled();
     method public boolean isTraceTagEnabled();
     method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
   }
@@ -50444,6 +50872,8 @@
     method public abstract java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public abstract java.lang.String getOriginalUrl();
     method public abstract int getProgress();
+    method public abstract boolean getRendererPriorityWaivedWhenNotVisible();
+    method public abstract int getRendererRequestedPriority();
     method public abstract float getScale();
     method public abstract android.webkit.WebViewProvider.ScrollDelegate getScrollDelegate();
     method public abstract android.webkit.WebSettings getSettings();
@@ -50498,6 +50928,7 @@
     method public abstract void setMapTrackballToArrowKeys(boolean);
     method public abstract void setNetworkAvailable(boolean);
     method public abstract void setPictureListener(android.webkit.WebView.PictureListener);
+    method public abstract void setRendererPriorityPolicy(int, boolean);
     method public abstract void setVerticalScrollbarOverlay(boolean);
     method public abstract void setWebChromeClient(android.webkit.WebChromeClient);
     method public abstract void setWebViewClient(android.webkit.WebViewClient);
@@ -52790,6 +53221,10 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getAutoSizeMaxTextSize();
+    method public int getAutoSizeMinTextSize();
+    method public int getAutoSizeStepGranularity();
+    method public int getAutoSizeTextType();
     method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
@@ -52815,7 +53250,6 @@
     method public int getExtendedPaddingTop();
     method public android.text.InputFilter[] getFilters();
     method public java.lang.String getFontFeatureSettings();
-    method public java.lang.String getFontVariationSettings();
     method public boolean getFreezesText();
     method public int getGravity();
     method public int getHighlightColor();
@@ -52862,7 +53296,7 @@
     method public float getShadowRadius();
     method public final boolean getShowSoftInputOnFocus();
     method public java.lang.CharSequence getText();
-    method public android.text.TextAssistant getTextAssistant();
+    method public android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
@@ -52899,6 +53333,10 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setAutoSizeMaxTextSize(int, float);
+    method public void setAutoSizeMinTextSize(int, float);
+    method public void setAutoSizeStepGranularity(int, float);
+    method public void setAutoSizeTextType(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
@@ -52921,7 +53359,6 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFontFeatureSettings(java.lang.String);
-    method public void setFontVariationSettings(java.lang.String);
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -52975,7 +53412,7 @@
     method public final void setText(int, android.widget.TextView.BufferType);
     method public void setTextAppearance(int);
     method public deprecated void setTextAppearance(android.content.Context, int);
-    method public void setTextAssistant(android.text.TextAssistant);
+    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public void setTextColor(int);
     method public void setTextColor(android.content.res.ColorStateList);
     method public void setTextIsSelectable(boolean);
@@ -52990,8 +53427,8 @@
     method public void setTypeface(android.graphics.Typeface, int);
     method public void setTypeface(android.graphics.Typeface);
     method public void setWidth(int);
-    field public static final int AUTO_SIZE_TYPE_NONE = 0; // 0x0
-    field public static final int AUTO_SIZE_TYPE_XY = 1; // 0x1
+    field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+    field public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; // 0x1
   }
 
   public static final class TextView.BufferType extends java.lang.Enum {
@@ -53610,6 +54047,10 @@
     method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
+  public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+    ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
+  }
+
   public class PathClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public PathClassLoader(java.lang.String, java.lang.ClassLoader);
     ctor public PathClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
@@ -56708,6 +57149,133 @@
 
 }
 
+package java.lang.invoke {
+
+  public class LambdaConversionException extends java.lang.Exception {
+    ctor public LambdaConversionException();
+    ctor public LambdaConversionException(java.lang.String);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+  }
+
+  public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asFixedArity();
+    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.util.List<?>) throws java.lang.Throwable;
+    method public boolean isVarargsCollector();
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public abstract interface MethodHandleInfo {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.invoke.MethodType getMethodType();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract int getReferenceKind();
+    method public default boolean isVarArgs();
+    method public static boolean refKindIsField(int);
+    method public static boolean refKindIsValid(int);
+    method public static java.lang.String refKindName(int);
+    method public static java.lang.String referenceKindToString(int);
+    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    field public static final int REF_getField = 1; // 0x1
+    field public static final int REF_getStatic = 2; // 0x2
+    field public static final int REF_invokeInterface = 9; // 0x9
+    field public static final int REF_invokeSpecial = 7; // 0x7
+    field public static final int REF_invokeStatic = 6; // 0x6
+    field public static final int REF_invokeVirtual = 5; // 0x5
+    field public static final int REF_newInvokeSpecial = 8; // 0x8
+    field public static final int REF_putField = 3; // 0x3
+    field public static final int REF_putStatic = 4; // 0x4
+  }
+
+  public class MethodHandles {
+    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 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 filterReturnValue(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 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 java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+  }
+
+  public static final class MethodHandles.Lookup {
+    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
+    method public java.lang.Class<?> lookupClass();
+    method public int lookupModes();
+    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;
+    method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    field public static final int PACKAGE = 8; // 0x8
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+    field public static final int PUBLIC = 1; // 0x1
+  }
+
+  public final class MethodType implements java.io.Serializable {
+    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
+    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType dropParameterTypes(int, int);
+    method public java.lang.invoke.MethodType erase();
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public java.lang.invoke.MethodType generic();
+    method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
+    method public static java.lang.invoke.MethodType genericMethodType(int);
+    method public boolean hasPrimitives();
+    method public boolean hasWrappers();
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
+    method public java.lang.Class<?>[] parameterArray();
+    method public int parameterCount();
+    method public java.util.List<java.lang.Class<?>> parameterList();
+    method public java.lang.Class<?> parameterType(int);
+    method public java.lang.Class<?> returnType();
+    method public java.lang.String toMethodDescriptorString();
+    method public java.lang.invoke.MethodType unwrap();
+    method public java.lang.invoke.MethodType wrap();
+  }
+
+  public class WrongMethodTypeException extends java.lang.RuntimeException {
+    ctor public WrongMethodTypeException();
+    ctor public WrongMethodTypeException(java.lang.String);
+  }
+
+}
+
 package java.lang.ref {
 
   public class PhantomReference<T> extends java.lang.ref.Reference {
@@ -68476,14 +69044,14 @@
     method public java.util.logging.ErrorManager getErrorManager();
     method public java.util.logging.Filter getFilter();
     method public java.util.logging.Formatter getFormatter();
-    method public synchronized java.util.logging.Level getLevel();
+    method public java.util.logging.Level getLevel();
     method public boolean isLoggable(java.util.logging.LogRecord);
     method public abstract void publish(java.util.logging.LogRecord);
     method protected void reportError(java.lang.String, java.lang.Exception, int);
-    method public void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
-    method public void setErrorManager(java.util.logging.ErrorManager);
-    method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
-    method public void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
+    method public synchronized void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
+    method public synchronized void setErrorManager(java.util.logging.ErrorManager);
+    method public synchronized void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
+    method public synchronized void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
     method public synchronized void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
@@ -68510,7 +69078,7 @@
   public class LogManager {
     ctor protected LogManager();
     method public boolean addLogger(java.util.logging.Logger);
-    method public void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method public deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void checkAccess() throws java.lang.SecurityException;
     method public static java.util.logging.LogManager getLogManager();
     method public java.util.logging.Logger getLogger(java.lang.String);
@@ -68519,7 +69087,7 @@
     method public java.lang.String getProperty(java.lang.String);
     method public void readConfiguration() throws java.io.IOException, java.lang.SecurityException;
     method public void readConfiguration(java.io.InputStream) throws java.io.IOException, java.lang.SecurityException;
-    method public void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method public deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void reset() throws java.lang.SecurityException;
     field public static final java.lang.String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
   }
@@ -68556,14 +69124,18 @@
     ctor protected Logger(java.lang.String, java.lang.String);
     method public void addHandler(java.util.logging.Handler) throws java.lang.SecurityException;
     method public void config(java.lang.String);
+    method public void config(java.util.function.Supplier<java.lang.String>);
     method public void entering(java.lang.String, java.lang.String);
     method public void entering(java.lang.String, java.lang.String, java.lang.Object);
     method public void entering(java.lang.String, java.lang.String, java.lang.Object[]);
     method public void exiting(java.lang.String, java.lang.String);
     method public void exiting(java.lang.String, java.lang.String, java.lang.Object);
     method public void fine(java.lang.String);
+    method public void fine(java.util.function.Supplier<java.lang.String>);
     method public void finer(java.lang.String);
+    method public void finer(java.util.function.Supplier<java.lang.String>);
     method public void finest(java.lang.String);
+    method public void finest(java.util.function.Supplier<java.lang.String>);
     method public static java.util.logging.Logger getAnonymousLogger();
     method public static java.util.logging.Logger getAnonymousLogger(java.lang.String);
     method public java.util.logging.Filter getFilter();
@@ -68578,28 +69150,38 @@
     method public java.lang.String getResourceBundleName();
     method public boolean getUseParentHandlers();
     method public void info(java.lang.String);
+    method public void info(java.util.function.Supplier<java.lang.String>);
     method public boolean isLoggable(java.util.logging.Level);
     method public void log(java.util.logging.LogRecord);
     method public void log(java.util.logging.Level, java.lang.String);
+    method public void log(java.util.logging.Level, java.util.function.Supplier<java.lang.String>);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Object);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Object[]);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Throwable);
+    method public void log(java.util.logging.Level, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String);
+    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.util.function.Supplier<java.lang.String>);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
+    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
+    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Object...);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
+    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Throwable);
     method public void removeHandler(java.util.logging.Handler) throws java.lang.SecurityException;
     method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
     method public void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
     method public void setParent(java.util.logging.Logger);
+    method public void setResourceBundle(java.util.ResourceBundle);
     method public void setUseParentHandlers(boolean);
     method public void severe(java.lang.String);
+    method public void severe(java.util.function.Supplier<java.lang.String>);
     method public void throwing(java.lang.String, java.lang.String, java.lang.Throwable);
     method public void warning(java.lang.String);
+    method public void warning(java.util.function.Supplier<java.lang.String>);
     field public static final java.lang.String GLOBAL_LOGGER_NAME = "global";
     field public static final deprecated java.util.logging.Logger global;
   }
@@ -68620,10 +69202,10 @@
     ctor public MemoryHandler(java.util.logging.Handler, int, java.util.logging.Level);
     method public void close() throws java.lang.SecurityException;
     method public void flush();
-    method public synchronized java.util.logging.Level getPushLevel();
+    method public java.util.logging.Level getPushLevel();
     method public synchronized void publish(java.util.logging.LogRecord);
     method public synchronized void push();
-    method public void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
+    method public synchronized void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
   public class SimpleFormatter extends java.util.logging.Formatter {
diff --git a/api/test-current.txt b/api/test-current.txt
index de86022..d57c849 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -83,6 +83,7 @@
     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";
     field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
+    field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
     field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -113,6 +114,7 @@
     field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
     field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
     field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
+    field public static final java.lang.String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
     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";
@@ -201,6 +203,8 @@
 
   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
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -361,6 +365,7 @@
     field public static final int centerMedium = 16842959; // 0x10100cf
     field public static final int centerX = 16843170; // 0x10101a2
     field public static final int centerY = 16843171; // 0x10101a3
+    field public static final int certDigest = 16844106; // 0x101054a
     field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
     field public static final int checkMark = 16843016; // 0x1010108
     field public static final int checkMarkTint = 16843943; // 0x10104a7
@@ -755,7 +760,6 @@
     field public static final int keyboardLayout = 16843691; // 0x10103ab
     field public static final int keyboardMode = 16843341; // 0x101024d
     field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
-    field public static final int keyboardNavigationSection = 16844097; // 0x1010541
     field public static final int keycode = 16842949; // 0x10100c5
     field public static final int killAfterRestore = 16843420; // 0x101029c
     field public static final int label = 16842753; // 0x1010001
@@ -905,7 +909,6 @@
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
     field public static final int nextFocusRight = 16842978; // 0x10100e2
     field public static final int nextFocusUp = 16842979; // 0x10100e3
-    field public static final int nextSectionForward = 16844099; // 0x1010543
     field public static final int noHistory = 16843309; // 0x101022d
     field public static final int normalScreens = 16843397; // 0x1010285
     field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -989,6 +992,7 @@
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int previewImage = 16843482; // 0x10102da
+    field public static final int primaryContentAlpha = 16843367; // 0x1010267
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
@@ -1052,6 +1056,7 @@
     field public static final int resizeable = 16843405; // 0x101028d
     field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
+    field public static final int restartOnConfigChanges = 16844105; // 0x1010549
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
@@ -1376,7 +1381,7 @@
     field public static final int toYDelta = 16843209; // 0x10101c9
     field public static final int toYScale = 16843205; // 0x10101c5
     field public static final int toolbarStyle = 16843946; // 0x10104aa
-    field public static final int tooltip = 16844084; // 0x1010534
+    field public static final int tooltipText = 16844084; // 0x1010534
     field public static final int top = 16843182; // 0x10101ae
     field public static final int topBright = 16842955; // 0x10100cb
     field public static final int topDark = 16842951; // 0x10100c7
@@ -1435,7 +1440,7 @@
     field public static final int viewportWidth = 16843778; // 0x1010402
     field public static final int visibility = 16842972; // 0x10100dc
     field public static final int visible = 16843156; // 0x1010194
-    field public static final int visibleToEphemeral = 16844095; // 0x101053f
+    field public static final int visibleToInstantApps = 16844095; // 0x101053f
     field public static final int vmSafeMode = 16843448; // 0x10102b8
     field public static final int voiceIcon = 16843908; // 0x1010484
     field public static final int voiceLanguage = 16843349; // 0x1010255
@@ -1812,6 +1817,7 @@
     field public static final int tabs = 16908307; // 0x1020013
     field public static final int text1 = 16908308; // 0x1020014
     field public static final int text2 = 16908309; // 0x1020015
+    field public static final int textAssist = 16908353; // 0x1020041
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
     field public static final int undo = 16908338; // 0x1020032
@@ -2878,15 +2884,18 @@
   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, int[]);
+    method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle, java.util.Map<java.lang.Integer, 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;
     method public void clearPassword(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     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 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);
     method public android.accounts.AccountManagerFuture<android.accounts.Account[]> getAccountsByTypeAndFeatures(java.lang.String, java.lang.String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler);
     method public android.accounts.Account[] getAccountsByTypeForPackage(java.lang.String, java.lang.String);
@@ -2897,13 +2906,11 @@
     method public android.accounts.AuthenticatorDescription[] getAuthenticatorTypes();
     method public java.lang.String getPassword(android.accounts.Account);
     method public java.lang.String getPreviousName(android.accounts.Account);
-    method public int[] getRequestingUidsForType(java.lang.String);
+    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);
-    method public boolean isAccountVisible(android.accounts.Account, int);
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method public boolean makeAccountVisible(android.accounts.Account, int);
     method public static deprecated android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
     method public boolean notifyAccountAuthenticated(android.accounts.Account);
@@ -2911,9 +2918,9 @@
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean removeAccountExplicitly(android.accounts.Account);
-    method public boolean removeAccountVisibility(android.accounts.Account, int);
     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 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);
@@ -2952,7 +2959,14 @@
     field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
-    field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
+    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 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
+    field public static final int VISIBILITY_USER_MANAGED_VISIBLE = 2; // 0x2
+    field public static final int VISIBILITY_VISIBLE = 1; // 0x1
   }
 
   public abstract interface AccountManagerCallback<V> {
@@ -3492,8 +3506,7 @@
     method public boolean dispatchTrackballEvent(android.view.MotionEvent);
     method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public void enterPictureInPictureMode();
-    method public void enterPictureInPictureMode(float);
-    method public void enterPictureInPictureModeOnMoveToBackground(boolean);
+    method public boolean enterPictureInPictureMode(android.app.PictureInPictureArgs);
     method public android.view.View findViewById(int);
     method public void finish();
     method public void finishActivity(int);
@@ -3526,7 +3539,6 @@
     method public int getRequestedOrientation();
     method public final android.view.SearchEvent getSearchEvent();
     method public int getTaskId();
-    method public android.text.TextAssistant getTextAssistant();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
     method public android.app.VoiceInteractor getVoiceInteractor();
@@ -3666,8 +3678,7 @@
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
     method public void setOverlayWithDecorCaptionEnabled(boolean);
-    method public void setPictureInPictureActions(java.util.List<android.app.RemoteAction>);
-    method public void setPictureInPictureAspectRatio(float);
+    method public void setPictureInPictureArgs(android.app.PictureInPictureArgs);
     method public final deprecated void setProgress(int);
     method public final deprecated void setProgressBarIndeterminate(boolean);
     method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
@@ -3677,7 +3688,6 @@
     method public final void setResult(int, android.content.Intent);
     method public final deprecated void setSecondaryProgress(int);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
-    method public void setTextAssistant(android.text.TextAssistant);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public deprecated void setTitleColor(int);
@@ -4601,6 +4611,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -4836,11 +4847,13 @@
   public static class Instrumentation.ActivityMonitor {
     ctor public Instrumentation.ActivityMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     ctor public Instrumentation.ActivityMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
+    ctor public Instrumentation.ActivityMonitor();
     method public final android.content.IntentFilter getFilter();
     method public final int getHits();
     method public final android.app.Activity getLastActivity();
     method public final android.app.Instrumentation.ActivityResult getResult();
     method public final boolean isBlocking();
+    method public android.app.Instrumentation.ActivityResult onMatchIntent(android.content.Intent);
     method public final android.app.Activity waitForActivity();
     method public final android.app.Activity waitForActivityWithTimeout(long);
   }
@@ -5035,6 +5048,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5118,6 +5132,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
+    method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
@@ -5407,7 +5422,6 @@
     method public java.lang.CharSequence getName();
     method public android.net.Uri getSound();
     method public long[] getVibrationPattern();
-    method public boolean isAllowed();
     method public void setBypassDnd(boolean);
     method public void setImportance(int);
     method public void setLights(boolean);
@@ -5446,6 +5460,7 @@
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
+    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
@@ -5531,6 +5546,17 @@
     method public abstract void onSendFinished(android.app.PendingIntent, android.content.Intent, int, java.lang.String, android.os.Bundle);
   }
 
+  public final class PictureInPictureArgs implements android.os.Parcelable {
+    ctor public PictureInPictureArgs();
+    ctor public PictureInPictureArgs(float, java.util.List<android.app.RemoteAction>);
+    method public android.app.PictureInPictureArgs clone();
+    method public int describeContents();
+    method public void setActions(java.util.List<android.app.RemoteAction>);
+    method public void setAspectRatio(float);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
+  }
+
   public class Presentation extends android.app.Dialog {
     ctor public Presentation(android.content.Context, android.view.Display);
     ctor public Presentation(android.content.Context, android.view.Display, int);
@@ -5567,6 +5593,18 @@
     field public static final int STYLE_SPINNER = 0; // 0x0
   }
 
+  public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
+    ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+    method public int describeContents();
+    method public android.app.PendingIntent getUserAction();
+    method public java.lang.CharSequence getUserActionTitle();
+    method public java.lang.CharSequence getUserMessage();
+    method public void showAsDialog(android.app.Activity);
+    method public void showAsNotification(android.content.Context);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
+  }
+
   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);
     method public android.app.RemoteAction clone();
@@ -5584,14 +5622,18 @@
   }
 
   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);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5603,6 +5645,7 @@
     method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
@@ -6128,6 +6171,7 @@
     method public int getPasswordMinimumSymbols(android.content.ComponentName);
     method public int getPasswordMinimumUpperCase(android.content.ComponentName);
     method public int getPasswordQuality(android.content.ComponentName);
+    method public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(android.content.ComponentName);
     method public int getPermissionGrantState(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int getPermissionPolicy(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
@@ -6149,6 +6193,7 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+    method public boolean isBackupServiceEnabled(android.content.ComponentName);
     method public boolean isCallerApplicationRestrictionsManagingPackage();
     method public boolean isDeviceManaged();
     method public boolean isDeviceOwnerApp(java.lang.String);
@@ -6180,6 +6225,7 @@
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
+    method public void setBackupServiceEnabled(android.content.ComponentName, boolean);
     method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
@@ -6350,6 +6396,17 @@
     field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
   }
 
+  public final class SystemUpdateInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getReceivedTime();
+    method public int getSecurityPatchState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdateInfo> CREATOR;
+    field public static final int SECURITY_PATCH_STATE_FALSE = 1; // 0x1
+    field public static final int SECURITY_PATCH_STATE_TRUE = 2; // 0x2
+    field public static final int SECURITY_PATCH_STATE_UNKNOWN = 0; // 0x0
+  }
+
   public class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -7933,6 +7990,7 @@
     ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
     ctor public ClipData(android.content.ClipData);
     method public void addItem(android.content.ClipData.Item);
+    method public void addItem(android.content.ClipData.Item, android.content.ContentResolver);
     method public int describeContents();
     method public android.content.ClipDescription getDescription();
     method public android.content.ClipData.Item getItemAt(int);
@@ -8453,6 +8511,7 @@
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
+    field public static final java.lang.String FONT_SERVICE = "font";
     field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
@@ -9024,10 +9083,10 @@
     field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
@@ -9540,6 +9599,7 @@
     method public int describeContents();
     method public void dump(android.util.Printer, java.lang.String);
     method public final int getThemeResource();
+    field public static final int CONFIG_COLORIMETRY = 16384; // 0x4000
     field public static final int CONFIG_DENSITY = 4096; // 0x1000
     field public static final int CONFIG_FONT_SCALE = 1073741824; // 0x40000000
     field public static final int CONFIG_KEYBOARD = 16; // 0x10
@@ -9814,7 +9874,10 @@
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
+    method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
@@ -9849,7 +9912,7 @@
     method public boolean accept(android.os.Bundle);
     method public boolean accept();
     method public int describeContents();
-    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo();
+    method public android.appwidget.AppWidgetProviderInfo getAppWidgetProviderInfo(android.content.Context);
     method public int getRequestType();
     method public android.content.pm.ShortcutInfo getShortcutInfo();
     method public boolean isValid();
@@ -9918,6 +9981,7 @@
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler);
     method public void uninstall(java.lang.String, android.content.IntentSender);
+    method public void uninstall(android.content.pm.VersionedPackage, android.content.IntentSender);
     method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
     method public void updateSessionAppIcon(int, android.graphics.Bitmap);
     method public void updateSessionAppLabel(int, java.lang.CharSequence);
@@ -10066,6 +10130,7 @@
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.PackageInstaller getPackageInstaller();
     method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] getPackagesForUid(int);
@@ -10080,6 +10145,7 @@
     method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -10238,6 +10304,7 @@
     field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
     field public static final int VERIFICATION_ALLOW = 1; // 0x1
     field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
+    field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
   }
 
   public static class PackageManager.NameNotFoundException extends android.util.AndroidException {
@@ -10378,6 +10445,20 @@
     field public java.lang.String permission;
   }
 
+  public final class SharedLibraryInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.pm.VersionedPackage getDeclaringPackage();
+    method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
+    method public java.lang.String getName();
+    method public int getVersion();
+    method public boolean isBuiltin();
+    method public boolean isDynamic();
+    method public boolean isStatic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR;
+    field public static final int VERSION_UNDEFINED = -1; // 0xffffffff
+  }
+
   public final class ShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.content.ComponentName getActivity();
@@ -10422,6 +10503,7 @@
   public class ShortcutManager {
     ctor public ShortcutManager(android.content.Context);
     method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
     method public void disableShortcuts(java.util.List<java.lang.String>);
     method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
     method public void enableShortcuts(java.util.List<java.lang.String>);
@@ -10453,6 +10535,15 @@
     field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR;
   }
 
+  public final class VersionedPackage implements android.os.Parcelable {
+    ctor public VersionedPackage(java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getPackageName();
+    method public long getVersionCode();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR;
+  }
+
 }
 
 package android.content.res {
@@ -10538,7 +10629,9 @@
     method public int getLayoutDirection();
     method public android.os.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
+    method public boolean isScreenHdr();
     method public boolean isScreenRound();
+    method public boolean isScreenWideColorGamut();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
@@ -10548,6 +10641,16 @@
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int COLORIMETRY_HDR_MASK = 12; // 0xc
+    field public static final int COLORIMETRY_HDR_NO = 4; // 0x4
+    field public static final int COLORIMETRY_HDR_SHIFT = 2; // 0x2
+    field public static final int COLORIMETRY_HDR_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_HDR_YES = 8; // 0x8
+    field public static final int COLORIMETRY_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 3; // 0x3
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 1; // 0x1
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0; // 0x0
+    field public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 2; // 0x2
     field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR;
     field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0
     field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1
@@ -10613,6 +10716,7 @@
     field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
     field public static final int UI_MODE_TYPE_VR_HEADSET = 7; // 0x7
     field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
+    field public int colorimetry;
     field public int densityDpi;
     field public float fontScale;
     field public int hardKeyboardHidden;
@@ -10667,6 +10771,7 @@
     method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
     method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
+    method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
     method public float getFraction(int, int, int);
     method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
     method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;
@@ -12153,15 +12258,57 @@
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
     method public static void RGBToHSV(int, int, int, float[]);
+    method public float alpha();
+    method public static float alpha(long);
     method public static int alpha(int);
     method public static int argb(int, int, int, int);
+    method public static int argb(float, float, float, float);
+    method public float blue();
+    method public static float blue(long);
     method public static int blue(int);
+    method public static android.graphics.ColorSpace colorSpace(long);
     method public static void colorToHSV(int, float[]);
+    method public android.graphics.Color convert(android.graphics.ColorSpace);
+    method public static long convert(int, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace.Connector);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
+    method public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(int);
+    method public int getComponentCount();
+    method public float[] getComponents();
+    method public android.graphics.ColorSpace.Model getModel();
+    method public float green();
+    method public static float green(long);
     method public static int green(int);
+    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public boolean isSrgb();
+    method public static boolean isSrgb(long);
+    method public boolean isWideGamut();
+    method public static boolean isWideGamut(long);
+    method public float luminance();
+    method public static float luminance(long);
     method public static float luminance(int);
+    method public long pack();
+    method public static long pack(int);
+    method public static long pack(float, float, float);
+    method public static long pack(float, float, float, float);
+    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
     method public static int parseColor(java.lang.String);
+    method public float red();
+    method public static float red(long);
     method public static int red(int);
     method public static int rgb(int, int, int);
+    method public static int rgb(float, float, float);
+    method public int toArgb();
+    method public static int toArgb(long);
+    method public static android.graphics.Color valueOf(int);
+    method public static android.graphics.Color valueOf(long);
+    method public static android.graphics.Color valueOf(float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
+    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
     field public static final int BLACK = -16777216; // 0xff000000
     field public static final int BLUE = -16776961; // 0xff0000ff
     field public static final int CYAN = -16711681; // 0xff00ffff
@@ -12233,7 +12380,7 @@
     field public static final float[] ILLUMINANT_D65;
     field public static final float[] ILLUMINANT_D75;
     field public static final float[] ILLUMINANT_E;
-    field public static final int MAX_ID = 64; // 0x40
+    field public static final int MAX_ID = 63; // 0x3f
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
@@ -12556,7 +12703,6 @@
     method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt);
     method public android.graphics.Paint.FontMetricsInt getFontMetricsInt();
     method public float getFontSpacing();
-    method public java.lang.String getFontVariationSettings();
     method public int getHinting();
     method public float getLetterSpacing();
     method public android.graphics.MaskFilter getMaskFilter();
@@ -12614,7 +12760,6 @@
     method public void setFilterBitmap(boolean);
     method public void setFlags(int);
     method public void setFontFeatureSettings(java.lang.String);
-    method public void setFontVariationSettings(java.lang.String);
     method public void setHinting(int);
     method public void setLetterSpacing(float);
     method public void setLinearText(boolean);
@@ -14013,6 +14158,37 @@
     method public float getZ();
   }
 
+  public final class HardwareBuffer implements android.os.Parcelable {
+    method public static android.hardware.HardwareBuffer create(int, int, int, int, long);
+    method public int describeContents();
+    method public void destroy();
+    method public int getFormat();
+    method public int getHeight();
+    method public int getLayers();
+    method public long getUsage();
+    method public int getWidth();
+    method public boolean isDestroyed();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
+    field public static final int RGBA_8888 = 1; // 0x1
+    field public static final int RGBA_FP16 = 5; // 0x5
+    field public static final int RGBX_8888 = 2; // 0x2
+    field public static final int RGB_565 = 4; // 0x4
+    field public static final int RGB_888 = 3; // 0x3
+    field public static final long USAGE0_CPU_READ = 2L; // 0x2L
+    field public static final long USAGE0_CPU_READ_OFTEN = 6L; // 0x6L
+    field public static final long USAGE0_CPU_WRITE = 32L; // 0x20L
+    field public static final long USAGE0_CPU_WRITE_OFTEN = 96L; // 0x60L
+    field public static final long USAGE0_GPU_COLOR_OUTPUT = 2048L; // 0x800L
+    field public static final long USAGE0_GPU_CUBEMAP = 8192L; // 0x2000L
+    field public static final long USAGE0_GPU_DATA_BUFFER = 16384L; // 0x4000L
+    field public static final long USAGE0_GPU_SAMPLED_IMAGE = 1024L; // 0x400L
+    field public static final long USAGE0_GPU_STORAGE_IMAGE = 3072L; // 0xc00L
+    field public static final long USAGE0_PROTECTED_CONTENT = 262144L; // 0x40000L
+    field public static final long USAGE0_SENSOR_DIRECT_DATA = 536870912L; // 0x20000000L
+    field public static final long USAGE0_VIDEO_ENCODE = 2097152L; // 0x200000L
+  }
+
   public final class Sensor {
     method public int getFifoMaxEventCount();
     method public int getFifoReservedEventCount();
@@ -19738,6 +19914,7 @@
     method public double getAccumulatedDeltaRangeMeters();
     method public int getAccumulatedDeltaRangeState();
     method public double getAccumulatedDeltaRangeUncertaintyMeters();
+    method public double getAutomaticGainControlLevelInDb();
     method public long getCarrierCycles();
     method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
@@ -19753,12 +19930,14 @@
     method public int getState();
     method public int getSvid();
     method public double getTimeOffsetNanos();
+    method public boolean hasAutomaticGainControlLevelInDb();
     method public boolean hasCarrierCycles();
     method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
     method public boolean hasSnrInDb();
     method public void reset();
+    method public void resetAutomaticGainControlLevel();
     method public void resetCarrierCycles();
     method public void resetCarrierFrequencyHz();
     method public void resetCarrierPhase();
@@ -19768,6 +19947,7 @@
     method public void setAccumulatedDeltaRangeMeters(double);
     method public void setAccumulatedDeltaRangeState(int);
     method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
+    method public void setAutomaticGainControlLevelInDb(double);
     method public void setCarrierCycles(long);
     method public void setCarrierFrequencyHz(float);
     method public void setCarrierPhase(double);
@@ -19801,11 +19981,13 @@
     field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
     field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
     field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
     field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
     field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
     field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
     field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
     field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
     field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
@@ -19872,12 +20054,14 @@
 
   public final class GnssStatus {
     method public float getAzimuthDegrees(int);
+    method public float getCarrierFrequencyHz(int);
     method public float getCn0DbHz(int);
     method public int getConstellationType(int);
     method public float getElevationDegrees(int);
     method public int getSatelliteCount();
     method public int getSvid(int);
     method public boolean hasAlmanacData(int);
+    method public boolean hasCarrierFrequency(int);
     method public boolean hasEphemerisData(int);
     method public boolean usedInFix(int);
     field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
@@ -19938,34 +20122,46 @@
     method public float getAccuracy();
     method public double getAltitude();
     method public float getBearing();
+    method public float getBearingAccuracyDegrees();
     method public long getElapsedRealtimeNanos();
     method public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
     method public java.lang.String getProvider();
     method public float getSpeed();
+    method public float getSpeedAccuracyMetersPerSecond();
     method public long getTime();
+    method public float getVerticalAccuracyMeters();
     method public boolean hasAccuracy();
     method public boolean hasAltitude();
     method public boolean hasBearing();
+    method public boolean hasBearingAccuracy();
     method public boolean hasSpeed();
+    method public boolean hasSpeedAccuracy();
+    method public boolean hasVerticalAccuracy();
     method public boolean isFromMockProvider();
     method public void removeAccuracy();
     method public void removeAltitude();
     method public void removeBearing();
+    method public void removeBearingAccuracy();
     method public void removeSpeed();
+    method public void removeSpeedAccuracy();
+    method public void removeVerticalAccuracy();
     method public void reset();
     method public void set(android.location.Location);
     method public void setAccuracy(float);
     method public void setAltitude(double);
     method public void setBearing(float);
+    method public void setBearingAccuracyDegrees(float);
     method public void setElapsedRealtimeNanos(long);
     method public void setExtras(android.os.Bundle);
     method public void setLatitude(double);
     method public void setLongitude(double);
     method public void setProvider(java.lang.String);
     method public void setSpeed(float);
+    method public void setSpeedAccuracyMetersPerSecond(float);
     method public void setTime(long);
+    method public void setVerticalAccuracyMeters(float);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.Location> CREATOR;
     field public static final int FORMAT_DEGREES = 0; // 0x0
@@ -21936,6 +22132,8 @@
     method public void setLocation(float, float);
     method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
     method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
+    method public void setNextOutputFile(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalStateException;
+    method public void setNextOutputFile(java.lang.String) throws java.io.IOException, java.lang.IllegalStateException;
     method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener);
     method public void setOnInfoListener(android.media.MediaRecorder.OnInfoListener);
     method public void setOrientationHint(int);
@@ -21954,7 +22152,9 @@
     field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
+    field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802; // 0x322
     field public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801; // 0x321
+    field public static final int MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803; // 0x323
     field public static final int MEDIA_RECORDER_INFO_UNKNOWN = 1; // 0x1
   }
 
@@ -24476,6 +24676,7 @@
   public class TrafficStats {
     ctor public TrafficStats();
     method public static void clearThreadStatsTag();
+    method public static int getAndSetThreadStatsTag(int);
     method public static long getMobileRxBytes();
     method public static long getMobileRxPackets();
     method public static long getMobileTxBytes();
@@ -29956,6 +30157,15 @@
     field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
   }
 
+  public abstract class ProxyFileDescriptorCallback {
+    ctor public ProxyFileDescriptorCallback();
+    method public void onFsync() throws android.system.ErrnoException;
+    method public long onGetSize() throws android.system.ErrnoException;
+    method public int onRead(long, int, byte[]) throws android.system.ErrnoException;
+    method public abstract void onRelease();
+    method public int onWrite(long, int, byte[]) throws android.system.ErrnoException;
+  }
+
   public class RecoverySystem {
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
@@ -30070,6 +30280,7 @@
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedClosableObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedRegistrationObjects();
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
+    method public android.os.StrictMode.VmPolicy.Builder detectUntaggedSockets();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
@@ -30367,13 +30578,22 @@
   }
 
   public class StorageManager {
+    method public long getCacheQuotaBytes();
+    method public long getCacheSizeBytes();
+    method public long getExternalCacheQuotaBytes();
+    method public long getExternalCacheSizeBytes();
     method public java.lang.String getMountedObbPath(java.lang.String);
     method public android.os.storage.StorageVolume getPrimaryStorageVolume();
     method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
     method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+    method public boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
+    method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
     method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+    method public void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
+    method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
     field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
   }
@@ -32474,7 +32694,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -32584,8 +32804,10 @@
   public static final class ContactsContract.ProviderStatus {
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
+    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -32731,6 +32953,7 @@
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -32775,6 +32998,7 @@
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+    field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -32808,6 +33032,7 @@
     ctor public DocumentsProvider();
     method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
     method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
@@ -35265,6 +35490,7 @@
     field public static final int PURPOSE_ENCRYPT = 1; // 0x1
     field public static final int PURPOSE_SIGN = 4; // 0x4
     field public static final int PURPOSE_VERIFY = 8; // 0x8
+    field public static final int PURPOSE_WRAP_KEY = 16; // 0x10
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
   }
@@ -35324,6 +35550,7 @@
     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 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 {
@@ -35529,7 +35756,6 @@
     field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
     field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -37203,6 +37429,7 @@
     method public void onReject();
     method public void onReject(java.lang.String);
     method public void onSeparate();
+    method public void onShowIncomingCallUi();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
@@ -37214,6 +37441,7 @@
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
+    method public final void setAudioRoute(int);
     method public final void setCallerDisplayName(java.lang.String, int);
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
@@ -37262,6 +37490,7 @@
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
+    field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
@@ -37329,7 +37558,9 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+    method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
     method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
@@ -37442,6 +37673,7 @@
     field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
     field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
     field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+    field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
     field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
     field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
     field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
@@ -37623,6 +37855,8 @@
     method public boolean handleMmi(java.lang.String);
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
+    method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle);
+    method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle);
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
@@ -37633,7 +37867,7 @@
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONFIGURE_PHONE_ACCOUNT = "android.telecom.action.CONFIGURE_PHONE_ACCOUNT";
     field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
-    field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
+    field public static final deprecated java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
@@ -37736,7 +37970,8 @@
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
     field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
-    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+    field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
     field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
     field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
     field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -37828,9 +38063,13 @@
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
     field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+    field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+    field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+    field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
     field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+    field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -39047,6 +39286,7 @@
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public android.content.ComponentName startService(android.content.Intent);
+    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
     method public boolean stopService(android.content.Intent);
     method public void unbindService(android.content.ServiceConnection);
     method public void unregisterReceiver(android.content.BroadcastReceiver);
@@ -39149,6 +39389,7 @@
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInstaller getPackageInstaller();
     method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] getPackagesForUid(int);
@@ -39163,6 +39404,7 @@
     method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
     method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public java.lang.String[] getSystemSharedLibraryNames();
     method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -39392,6 +39634,65 @@
     method public android.text.Editable newEditable(java.lang.CharSequence);
   }
 
+  public final class FontConfig implements android.os.Parcelable {
+    ctor public FontConfig();
+    ctor public FontConfig(android.text.FontConfig);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method public java.util.List<android.text.FontConfig.Family> getFamilies();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
+  }
+
+  public static final class FontConfig.Alias implements android.os.Parcelable {
+    ctor public FontConfig.Alias(java.lang.String, java.lang.String, int);
+    method public int describeContents();
+    method public java.lang.String getName();
+    method public java.lang.String getToName();
+    method public int getWeight();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
+  }
+
+  public static final class FontConfig.Axis implements android.os.Parcelable {
+    ctor public FontConfig.Axis(int, float);
+    method public int describeContents();
+    method public float getStyleValue();
+    method public int getTag();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Axis> CREATOR;
+  }
+
+  public static final class FontConfig.Family implements android.os.Parcelable {
+    ctor public FontConfig.Family(java.lang.String, java.util.List<android.text.FontConfig.Font>, java.lang.String, java.lang.String);
+    ctor public FontConfig.Family(android.text.FontConfig.Family);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Font> getFonts();
+    method public java.lang.String getLanguage();
+    method public java.lang.String getName();
+    method public java.lang.String getVariant();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Family> CREATOR;
+  }
+
+  public static final class FontConfig.Font implements android.os.Parcelable {
+    ctor public FontConfig.Font(java.lang.String, int, java.util.List<android.text.FontConfig.Axis>, int, boolean);
+    ctor public FontConfig.Font(android.text.FontConfig.Font);
+    method public int describeContents();
+    method public java.util.List<android.text.FontConfig.Axis> getAxes();
+    method public android.os.ParcelFileDescriptor getFd();
+    method public java.lang.String getFontName();
+    method public int getTtcIndex();
+    method public int getWeight();
+    method public boolean isItalic();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
+  }
+
+  public final class FontManager {
+    method public android.text.FontConfig getSystemFonts();
+  }
+
   public abstract interface GetChars implements java.lang.CharSequence {
     method public abstract void getChars(int, int, char[], int);
   }
@@ -39747,22 +40048,6 @@
     method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
   }
 
-  public abstract interface TextAssistant {
-    method public abstract void addLinks(android.text.Spannable, int);
-    method public abstract android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
-  public class TextClassification {
-    ctor public TextClassification();
-    method public java.util.Map<java.lang.String, java.lang.Float> getTypeConfidence();
-  }
-
-  public final class TextClassificationManager implements android.text.TextAssistant {
-    method public void addLinks(android.text.Spannable, int);
-    method public java.util.List<android.text.TextLanguage> detectLanguages(java.lang.CharSequence);
-    method public android.text.TextSelection suggestSelection(java.lang.CharSequence, int, int);
-  }
-
   public abstract interface TextDirectionHeuristic {
     method public abstract boolean isRtl(char[], int, int);
     method public abstract boolean isRtl(java.lang.CharSequence, int, int);
@@ -39778,13 +40063,6 @@
     field public static final android.text.TextDirectionHeuristic RTL;
   }
 
-  public final class TextLanguage {
-    ctor public TextLanguage(int, int, java.util.Map<java.lang.String, java.lang.Float>);
-    method public int getEndIndex();
-    method public java.util.Map<java.lang.String, java.lang.Float> getLanguageConfidence();
-    method public int getStartIndex();
-  }
-
   public class TextPaint extends android.graphics.Paint {
     ctor public TextPaint();
     ctor public TextPaint(int);
@@ -39797,13 +40075,6 @@
     field public int linkColor;
   }
 
-  public class TextSelection {
-    ctor public TextSelection();
-    method public int getSelectionEndIndex();
-    method public int getSelectionStartIndex();
-    method public android.text.TextClassification getTextClassification();
-  }
-
   public class TextUtils {
     method public static deprecated java.lang.CharSequence commaEllipsize(java.lang.CharSequence, android.text.TextPaint, float, java.lang.String, java.lang.String);
     method public static java.lang.CharSequence concat(java.lang.CharSequence...);
@@ -42222,7 +42493,9 @@
     method public android.view.Display.Mode[] getSupportedModes();
     method public deprecated float[] getSupportedRefreshRates();
     method public deprecated int getWidth();
+    method public boolean isHdr();
     method public boolean isValid();
+    method public boolean isWideColorGamut();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
     field public static final int FLAG_PRESENTATION = 8; // 0x8
     field public static final int FLAG_PRIVATE = 4; // 0x4
@@ -42291,7 +42564,7 @@
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
     method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
-    method public android.view.View findNextKeyboardNavigationGroup(int, android.view.View, android.view.View, int);
+    method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
     method public static android.view.FocusFinder getInstance();
   }
 
@@ -43076,7 +43349,7 @@
     method public abstract android.view.SubMenu getSubMenu();
     method public abstract java.lang.CharSequence getTitle();
     method public abstract java.lang.CharSequence getTitleCondensed();
-    method public default java.lang.CharSequence getTooltip();
+    method public default java.lang.CharSequence getTooltipText();
     method public abstract boolean hasSubMenu();
     method public abstract boolean isActionViewExpanded();
     method public abstract boolean isCheckable();
@@ -43103,7 +43376,7 @@
     method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
     method public abstract android.view.MenuItem setTitle(int);
     method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
-    method public default android.view.MenuItem setTooltip(java.lang.CharSequence);
+    method public default android.view.MenuItem setTooltipText(java.lang.CharSequence);
     method public abstract android.view.MenuItem setVisible(boolean);
     field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
@@ -43591,7 +43864,7 @@
     method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
     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 addKeyboardNavigationGroups(int, java.util.Collection<android.view.View>, int);
+    method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
     method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43755,7 +44028,6 @@
     method public int getNextFocusLeftId();
     method public int getNextFocusRightId();
     method public int getNextFocusUpId();
-    method public int getNextSectionForwardId();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method public android.view.ViewOutlineProvider getOutlineProvider();
     method public int getOverScrollMode();
@@ -43799,7 +44071,8 @@
     method public java.lang.Object getTag(int);
     method public int getTextAlignment();
     method public int getTextDirection();
-    method public final java.lang.CharSequence getTooltip();
+    method public final deprecated java.lang.CharSequence getTooltip();
+    method public final java.lang.CharSequence getTooltipText();
     method public android.view.View getTooltipView();
     method public final int getTop();
     method protected float getTopFadingEdgeStrength();
@@ -43861,7 +44134,6 @@
     method public boolean isInLayout();
     method public boolean isInTouchMode();
     method public final boolean isKeyboardNavigationCluster();
-    method public final boolean isKeyboardNavigationSection();
     method public boolean isLaidOut();
     method public boolean isLayoutDirectionResolved();
     method public boolean isLayoutRequested();
@@ -43884,7 +44156,7 @@
     method public boolean isVerticalFadingEdgeEnabled();
     method public boolean isVerticalScrollBarEnabled();
     method public void jumpDrawablesToCurrentState();
-    method public android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+    method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public void layout(int, int, int, int);
     method public final void measure(int, int);
     method protected static int[] mergeDrawableStates(int[], int[]);
@@ -44034,7 +44306,6 @@
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
     method public void setKeyboardNavigationCluster(boolean);
-    method public void setKeyboardNavigationSection(boolean);
     method public void setLabelFor(int);
     method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
@@ -44052,7 +44323,6 @@
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
-    method public void setNextSectionForwardId(int);
     method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -44101,7 +44371,8 @@
     method public void setTag(int, java.lang.Object);
     method public void setTextAlignment(int);
     method public void setTextDirection(int);
-    method public final void setTooltip(java.lang.CharSequence);
+    method public final deprecated void setTooltip(java.lang.CharSequence);
+    method public final void setTooltipText(java.lang.CharSequence);
     method public final void setTop(int);
     method public void setTouchDelegate(android.view.TouchDelegate);
     method public final void setTransitionName(java.lang.String);
@@ -44178,8 +44449,6 @@
     field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
     field public static final int INVISIBLE = 4; // 0x4
     field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
-    field public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; // 0x1
-    field public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; // 0x2
     field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
     field public static final int LAYER_TYPE_NONE = 0; // 0x0
     field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
@@ -44702,7 +44971,7 @@
     method public abstract boolean isLayoutRequested();
     method public abstract boolean isTextAlignmentResolved();
     method public abstract boolean isTextDirectionResolved();
-    method public abstract android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+    method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
     method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
     method public abstract boolean onNestedPreFling(android.view.View, float, float);
@@ -46491,6 +46760,83 @@
 
 }
 
+package android.view.textclassifier {
+
+  public abstract interface LinksInfo {
+    method public abstract boolean apply(java.lang.CharSequence);
+  }
+
+  public final class TextClassificationManager {
+    method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence);
+    method public android.view.textclassifier.TextClassifier getDefaultTextClassifier();
+  }
+
+  public final class TextClassificationResult {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public android.view.View.OnClickListener getOnClickListener();
+    method public java.lang.String getText();
+  }
+
+  public static final class TextClassificationResult.Builder {
+    ctor public TextClassificationResult.Builder();
+    method public android.view.textclassifier.TextClassificationResult build();
+    method public android.view.textclassifier.TextClassificationResult.Builder setEntityType(java.lang.String, float);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIcon(android.graphics.drawable.Drawable);
+    method public android.view.textclassifier.TextClassificationResult.Builder setIntent(android.content.Intent);
+    method public android.view.textclassifier.TextClassificationResult.Builder setLabel(java.lang.String);
+    method public android.view.textclassifier.TextClassificationResult.Builder setOnClickListener(android.view.View.OnClickListener);
+    method public android.view.textclassifier.TextClassificationResult.Builder setText(java.lang.String);
+  }
+
+  public abstract interface TextClassifier {
+    method public abstract android.view.textclassifier.LinksInfo getLinks(java.lang.CharSequence, int);
+    method public abstract android.view.textclassifier.TextClassificationResult getTextClassificationResult(java.lang.CharSequence, int, int);
+    method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
+    field public static final android.view.textclassifier.TextClassifier NO_OP;
+    field public static final java.lang.String TYPE_ADDRESS = "address";
+    field public static final java.lang.String TYPE_EMAIL = "email";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+  }
+
+  public static abstract class TextClassifier.EntityType implements java.lang.annotation.Annotation {
+  }
+
+  public final class TextLanguage {
+    method public float getConfidenceScore(java.util.Locale);
+    method public int getEndIndex();
+    method public java.util.Locale getLanguage(int);
+    method public int getLanguageCount();
+    method public int getStartIndex();
+  }
+
+  public static final class TextLanguage.Builder {
+    ctor public TextLanguage.Builder(int, int);
+    method public android.view.textclassifier.TextLanguage build();
+    method public android.view.textclassifier.TextLanguage.Builder setLanguage(java.util.Locale, float);
+  }
+
+  public final class TextSelection {
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public android.view.textclassifier.TextSelection build();
+    method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+  }
+
+}
+
 package android.view.textservice {
 
   public final class SentenceSuggestionsInfo implements android.os.Parcelable {
@@ -46721,6 +47067,7 @@
   public abstract class RenderProcessGoneDetail {
     ctor public RenderProcessGoneDetail();
     method public abstract boolean didCrash();
+    method public abstract int rendererPriorityAtExit();
   }
 
   public class ServiceWorkerClient {
@@ -47137,6 +47484,8 @@
     method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
+    method public boolean getRendererPriorityWaivedWhenNotVisible();
+    method public int getRendererRequestedPriority();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public java.lang.String getTitle();
@@ -47184,6 +47533,7 @@
     method public deprecated void setMapTrackballToArrowKeys(boolean);
     method public void setNetworkAvailable(boolean);
     method public deprecated void setPictureListener(android.webkit.WebView.PictureListener);
+    method public void setRendererPriorityPolicy(int, boolean);
     method public deprecated void setVerticalScrollbarOverlay(boolean);
     method public void setWebChromeClient(android.webkit.WebChromeClient);
     method public static void setWebContentsDebuggingEnabled(boolean);
@@ -47193,6 +47543,9 @@
     method public void zoomBy(float);
     method public boolean zoomIn();
     method public boolean zoomOut();
+    field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
+    field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
+    field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
     field public static final java.lang.String SCHEME_GEO = "geo:0,0?q=";
     field public static final java.lang.String SCHEME_MAILTO = "mailto:";
     field public static final java.lang.String SCHEME_TEL = "tel:";
@@ -48671,6 +49024,7 @@
     method public int getGravity();
     method public android.view.Menu getMenu();
     method public android.view.MenuInflater getMenuInflater();
+    method public android.widget.ListView getMenuListView();
     method public void inflate(int);
     method public void setGravity(int);
     method public void setOnDismissListener(android.widget.PopupMenu.OnDismissListener);
@@ -49504,6 +49858,10 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getAutoSizeMaxTextSize();
+    method public int getAutoSizeMinTextSize();
+    method public int getAutoSizeStepGranularity();
+    method public int getAutoSizeTextType();
     method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
@@ -49529,7 +49887,6 @@
     method public int getExtendedPaddingTop();
     method public android.text.InputFilter[] getFilters();
     method public java.lang.String getFontFeatureSettings();
-    method public java.lang.String getFontVariationSettings();
     method public boolean getFreezesText();
     method public int getGravity();
     method public int getHighlightColor();
@@ -49576,7 +49933,7 @@
     method public float getShadowRadius();
     method public final boolean getShowSoftInputOnFocus();
     method public java.lang.CharSequence getText();
-    method public android.text.TextAssistant getTextAssistant();
+    method public android.view.textclassifier.TextClassifier getTextClassifier();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
     method public android.os.LocaleList getTextLocales();
@@ -49613,6 +49970,10 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setAutoSizeMaxTextSize(int, float);
+    method public void setAutoSizeMinTextSize(int, float);
+    method public void setAutoSizeStepGranularity(int, float);
+    method public void setAutoSizeTextType(int);
     method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
@@ -49635,7 +49996,6 @@
     method public void setExtractedText(android.view.inputmethod.ExtractedText);
     method public void setFilters(android.text.InputFilter[]);
     method public void setFontFeatureSettings(java.lang.String);
-    method public void setFontVariationSettings(java.lang.String);
     method protected boolean setFrame(int, int, int, int);
     method public void setFreezesText(boolean);
     method public void setGravity(int);
@@ -49689,7 +50049,7 @@
     method public final void setText(int, android.widget.TextView.BufferType);
     method public void setTextAppearance(int);
     method public deprecated void setTextAppearance(android.content.Context, int);
-    method public void setTextAssistant(android.text.TextAssistant);
+    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
     method public void setTextColor(int);
     method public void setTextColor(android.content.res.ColorStateList);
     method public void setTextIsSelectable(boolean);
@@ -49704,8 +50064,8 @@
     method public void setTypeface(android.graphics.Typeface, int);
     method public void setTypeface(android.graphics.Typeface);
     method public void setWidth(int);
-    field public static final int AUTO_SIZE_TYPE_NONE = 0; // 0x0
-    field public static final int AUTO_SIZE_TYPE_XY = 1; // 0x1
+    field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+    field public static final int AUTO_SIZE_TEXT_TYPE_XY = 1; // 0x1
   }
 
   public static final class TextView.BufferType extends java.lang.Enum {
@@ -50332,6 +50692,10 @@
     method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
   }
 
+  public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+    ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
+  }
+
   public class PathClassLoader extends dalvik.system.BaseDexClassLoader {
     ctor public PathClassLoader(java.lang.String, java.lang.ClassLoader);
     ctor public PathClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
@@ -53430,6 +53794,133 @@
 
 }
 
+package java.lang.invoke {
+
+  public class LambdaConversionException extends java.lang.Exception {
+    ctor public LambdaConversionException();
+    ctor public LambdaConversionException(java.lang.String);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+  }
+
+  public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asFixedArity();
+    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.util.List<?>) throws java.lang.Throwable;
+    method public boolean isVarargsCollector();
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public abstract interface MethodHandleInfo {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.invoke.MethodType getMethodType();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract int getReferenceKind();
+    method public default boolean isVarArgs();
+    method public static boolean refKindIsField(int);
+    method public static boolean refKindIsValid(int);
+    method public static java.lang.String refKindName(int);
+    method public static java.lang.String referenceKindToString(int);
+    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    field public static final int REF_getField = 1; // 0x1
+    field public static final int REF_getStatic = 2; // 0x2
+    field public static final int REF_invokeInterface = 9; // 0x9
+    field public static final int REF_invokeSpecial = 7; // 0x7
+    field public static final int REF_invokeStatic = 6; // 0x6
+    field public static final int REF_invokeVirtual = 5; // 0x5
+    field public static final int REF_newInvokeSpecial = 8; // 0x8
+    field public static final int REF_putField = 3; // 0x3
+    field public static final int REF_putStatic = 4; // 0x4
+  }
+
+  public class MethodHandles {
+    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 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 filterReturnValue(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 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 java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+  }
+
+  public static final class MethodHandles.Lookup {
+    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
+    method public java.lang.Class<?> lookupClass();
+    method public int lookupModes();
+    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;
+    method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    field public static final int PACKAGE = 8; // 0x8
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+    field public static final int PUBLIC = 1; // 0x1
+  }
+
+  public final class MethodType implements java.io.Serializable {
+    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
+    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType dropParameterTypes(int, int);
+    method public java.lang.invoke.MethodType erase();
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public java.lang.invoke.MethodType generic();
+    method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
+    method public static java.lang.invoke.MethodType genericMethodType(int);
+    method public boolean hasPrimitives();
+    method public boolean hasWrappers();
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
+    method public java.lang.Class<?>[] parameterArray();
+    method public int parameterCount();
+    method public java.util.List<java.lang.Class<?>> parameterList();
+    method public java.lang.Class<?> parameterType(int);
+    method public java.lang.Class<?> returnType();
+    method public java.lang.String toMethodDescriptorString();
+    method public java.lang.invoke.MethodType unwrap();
+    method public java.lang.invoke.MethodType wrap();
+  }
+
+  public class WrongMethodTypeException extends java.lang.RuntimeException {
+    ctor public WrongMethodTypeException();
+    ctor public WrongMethodTypeException(java.lang.String);
+  }
+
+}
+
 package java.lang.ref {
 
   public class PhantomReference<T> extends java.lang.ref.Reference {
@@ -65198,14 +65689,14 @@
     method public java.util.logging.ErrorManager getErrorManager();
     method public java.util.logging.Filter getFilter();
     method public java.util.logging.Formatter getFormatter();
-    method public synchronized java.util.logging.Level getLevel();
+    method public java.util.logging.Level getLevel();
     method public boolean isLoggable(java.util.logging.LogRecord);
     method public abstract void publish(java.util.logging.LogRecord);
     method protected void reportError(java.lang.String, java.lang.Exception, int);
-    method public void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
-    method public void setErrorManager(java.util.logging.ErrorManager);
-    method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
-    method public void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
+    method public synchronized void setEncoding(java.lang.String) throws java.lang.SecurityException, java.io.UnsupportedEncodingException;
+    method public synchronized void setErrorManager(java.util.logging.ErrorManager);
+    method public synchronized void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
+    method public synchronized void setFormatter(java.util.logging.Formatter) throws java.lang.SecurityException;
     method public synchronized void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
@@ -65232,7 +65723,7 @@
   public class LogManager {
     ctor protected LogManager();
     method public boolean addLogger(java.util.logging.Logger);
-    method public void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method public deprecated void addPropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void checkAccess() throws java.lang.SecurityException;
     method public static java.util.logging.LogManager getLogManager();
     method public java.util.logging.Logger getLogger(java.lang.String);
@@ -65241,7 +65732,7 @@
     method public java.lang.String getProperty(java.lang.String);
     method public void readConfiguration() throws java.io.IOException, java.lang.SecurityException;
     method public void readConfiguration(java.io.InputStream) throws java.io.IOException, java.lang.SecurityException;
-    method public void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
+    method public deprecated void removePropertyChangeListener(java.beans.PropertyChangeListener) throws java.lang.SecurityException;
     method public void reset() throws java.lang.SecurityException;
     field public static final java.lang.String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging";
   }
@@ -65278,14 +65769,18 @@
     ctor protected Logger(java.lang.String, java.lang.String);
     method public void addHandler(java.util.logging.Handler) throws java.lang.SecurityException;
     method public void config(java.lang.String);
+    method public void config(java.util.function.Supplier<java.lang.String>);
     method public void entering(java.lang.String, java.lang.String);
     method public void entering(java.lang.String, java.lang.String, java.lang.Object);
     method public void entering(java.lang.String, java.lang.String, java.lang.Object[]);
     method public void exiting(java.lang.String, java.lang.String);
     method public void exiting(java.lang.String, java.lang.String, java.lang.Object);
     method public void fine(java.lang.String);
+    method public void fine(java.util.function.Supplier<java.lang.String>);
     method public void finer(java.lang.String);
+    method public void finer(java.util.function.Supplier<java.lang.String>);
     method public void finest(java.lang.String);
+    method public void finest(java.util.function.Supplier<java.lang.String>);
     method public static java.util.logging.Logger getAnonymousLogger();
     method public static java.util.logging.Logger getAnonymousLogger(java.lang.String);
     method public java.util.logging.Filter getFilter();
@@ -65300,28 +65795,38 @@
     method public java.lang.String getResourceBundleName();
     method public boolean getUseParentHandlers();
     method public void info(java.lang.String);
+    method public void info(java.util.function.Supplier<java.lang.String>);
     method public boolean isLoggable(java.util.logging.Level);
     method public void log(java.util.logging.LogRecord);
     method public void log(java.util.logging.Level, java.lang.String);
+    method public void log(java.util.logging.Level, java.util.function.Supplier<java.lang.String>);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Object);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Object[]);
     method public void log(java.util.logging.Level, java.lang.String, java.lang.Throwable);
+    method public void log(java.util.logging.Level, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String);
+    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.util.function.Supplier<java.lang.String>);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
     method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
-    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
+    method public void logp(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.Throwable, java.util.function.Supplier<java.lang.String>);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Object[]);
+    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Object...);
+    method public deprecated void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable);
+    method public void logrb(java.util.logging.Level, java.lang.String, java.lang.String, java.util.ResourceBundle, java.lang.String, java.lang.Throwable);
     method public void removeHandler(java.util.logging.Handler) throws java.lang.SecurityException;
     method public void setFilter(java.util.logging.Filter) throws java.lang.SecurityException;
     method public void setLevel(java.util.logging.Level) throws java.lang.SecurityException;
     method public void setParent(java.util.logging.Logger);
+    method public void setResourceBundle(java.util.ResourceBundle);
     method public void setUseParentHandlers(boolean);
     method public void severe(java.lang.String);
+    method public void severe(java.util.function.Supplier<java.lang.String>);
     method public void throwing(java.lang.String, java.lang.String, java.lang.Throwable);
     method public void warning(java.lang.String);
+    method public void warning(java.util.function.Supplier<java.lang.String>);
     field public static final java.lang.String GLOBAL_LOGGER_NAME = "global";
     field public static final deprecated java.util.logging.Logger global;
   }
@@ -65342,10 +65847,10 @@
     ctor public MemoryHandler(java.util.logging.Handler, int, java.util.logging.Level);
     method public void close() throws java.lang.SecurityException;
     method public void flush();
-    method public synchronized java.util.logging.Level getPushLevel();
+    method public java.util.logging.Level getPushLevel();
     method public synchronized void publish(java.util.logging.LogRecord);
     method public synchronized void push();
-    method public void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
+    method public synchronized void setPushLevel(java.util.logging.Level) throws java.lang.SecurityException;
   }
 
   public class SimpleFormatter extends java.util.logging.Formatter {
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index d5580ac..0ea141c 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -184,10 +184,6 @@
 
 int main(int argc, char* const argv[])
 {
-    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
-        LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
-    }
-
     if (!LOG_NDEBUG) {
       String8 argv_String;
       for (int i = 0; i < argc; ++i) {
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 5bf8076..780db5e 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -270,7 +270,7 @@
         }
     }
 
-    private void backupNowAllPackages() {
+    private void backupNowAllPackages(boolean nonIncrementalBackup) {
         int userId = UserHandle.USER_SYSTEM;
         IPackageManager mPm =
                 IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
@@ -297,14 +297,19 @@
                     System.err.println(BMGR_NOT_RUNNING_ERR);
                 }
             }
-            backupNowPackages(packages);
+            backupNowPackages(packages, nonIncrementalBackup);
         }
     }
 
-    private void backupNowPackages(List<String> packages) {
+    private void backupNowPackages(List<String> packages, boolean nonIncrementalBackup) {
+        int flags = 0;
+        if (nonIncrementalBackup) {
+            flags |= BackupManager.FLAG_NON_INCREMENTAL_BACKUP;
+        }
         try {
             BackupObserver observer = new BackupObserver();
-            int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer);
+            int err = mBmgr.requestBackup(packages.toArray(new String[packages.size()]), observer,
+                    flags);
             if (err == 0) {
                 // Off and running -- wait for the backup to complete
                 observer.waitForCompletion();
@@ -320,24 +325,31 @@
     private void doBackupNow() {
         String pkg;
         boolean backupAll = false;
+        boolean nonIncrementalBackup = false;
         ArrayList<String> allPkgs = new ArrayList<String>();
         while ((pkg = nextArg()) != null) {
             if (pkg.equals("--all")) {
                 backupAll = true;
+            } else if (pkg.equals("--non-incremental")) {
+                nonIncrementalBackup = true;
+            } else if (pkg.equals("--incremental")) {
+                nonIncrementalBackup = false;
             } else {
                 allPkgs.add(pkg);
             }
         }
         if (backupAll) {
             if (allPkgs.size() == 0) {
-                System.out.println("Running backup for all packages.");
-                backupNowAllPackages();
+                System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") +
+                        "incremental backup for all packages.");
+                backupNowAllPackages(nonIncrementalBackup);
             } else {
                 System.err.println("Provide only '--all' flag or list of packages.");
             }
         } else if (allPkgs.size() > 0) {
-            System.out.println("Running backup for " + allPkgs.size() +" requested packages.");
-            backupNowPackages(allPkgs);
+            System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") +
+                    "incremental backup for " + allPkgs.size() +" requested packages.");
+            backupNowPackages(allPkgs, nonIncrementalBackup);
         } else {
             System.err.println("Provide '--all' flag or list of packages.");
         }
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 810d201..ac5fea3 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1556,7 +1556,7 @@
         System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
         System.err.println("       pm install-commit SESSION_ID");
         System.err.println("       pm install-abandon SESSION_ID");
-        System.err.println("       pm uninstall [-k] [--user USER_ID] PACKAGE");
+        System.err.println("       pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE");
         System.err.println("       pm set-installer PACKAGE INSTALLER");
         System.err.println("       pm move-package PACKAGE [internal|UUID]");
         System.err.println("       pm move-primary-storage [internal|UUID]");
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
index 8e9791f..02a92b9 100644
--- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -58,7 +58,8 @@
                 IPackageManager pm = IPackageManager.Stub.asInterface(
                         ServiceManager.getService("package"));
                 try {
-                    if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0)) {
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0) ||
+			pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) {
                         INfcAdapter nfc = INfcAdapter.Stub
                                 .asInterface(ServiceManager.getService(Context.NFC_SERVICE));
                         try {
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
index af2e25a..f932388 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -29,13 +29,14 @@
 LOCAL_SRC_FILES := $(uiautomator.core_src_files)
 LOCAL_MODULE := uiautomator.core
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 ###############################################
 # Generate the stub source files
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(uiautomator.core_src_files)
-LOCAL_JAVA_LIBRARIES := $(uiautomator.core_java_libraries)
+LOCAL_JAVA_LIBRARIES := $(uiautomator.core_java_libraries) legacy-android-test
 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/core-src \
 	$(LOCAL_PATH)/testrunner-src
diff --git a/compiled-classes-phone b/compiled-classes-phone
index ebc54f2..ed0a4a6 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -1195,13 +1195,13 @@
 android.graphics.DiscretePathEffect
 android.graphics.DrawFilter
 android.graphics.EmbossMaskFilter
+android.graphics.FontConfig
+android.graphics.FontConfig$Alias
+android.graphics.FontConfig$Axis
+android.graphics.FontConfig$Family
+android.graphics.FontConfig$Font
 android.graphics.FontFamily
 android.graphics.FontListParser
-android.graphics.FontListParser$Alias
-android.graphics.FontListParser$Axis
-android.graphics.FontListParser$Config
-android.graphics.FontListParser$Family
-android.graphics.FontListParser$Font
 android.graphics.ImageFormat
 android.graphics.Insets
 android.graphics.Interpolator
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 07a8253..b76aeb7 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -414,9 +414,9 @@
     public int flags;
 
     /**
-     * The unique string Id to identify the accessibility service.
+     * The component name the accessibility service.
      */
-    private String mId;
+    private ComponentName mComponentName;
 
     /**
      * The Service that implements this accessibility service component.
@@ -464,7 +464,7 @@
     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
             throws XmlPullParserException, IOException {
         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-        mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
+        mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
         mResolveInfo = resolveInfo;
 
         XmlResourceParser parser = null;
@@ -574,7 +574,14 @@
      * @hide
      */
     public void setComponentName(ComponentName component) {
-        mId = component.flattenToShortString();
+        mComponentName = component;
+    }
+
+    /**
+     * @hide
+     */
+    public ComponentName getComponentName() {
+        return mComponentName;
     }
 
     /**
@@ -585,7 +592,7 @@
      * @return The id.
      */
     public String getId() {
-        return mId;
+        return mComponentName.flattenToShortString();
     }
 
     /**
@@ -715,7 +722,7 @@
         parcel.writeInt(feedbackType);
         parcel.writeLong(notificationTimeout);
         parcel.writeInt(flags);
-        parcel.writeString(mId);
+        parcel.writeParcelable(mComponentName, flagz);
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
         parcel.writeInt(mCapabilities);
@@ -729,7 +736,7 @@
         feedbackType = parcel.readInt();
         notificationTimeout = parcel.readLong();
         flags = parcel.readInt();
-        mId = parcel.readString();
+        mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
         mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
         mCapabilities = parcel.readInt();
@@ -739,7 +746,7 @@
 
     @Override
     public int hashCode() {
-        return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
+        return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
     }
 
     @Override
@@ -754,11 +761,11 @@
             return false;
         }
         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
-        if (mId == null) {
-            if (other.mId != null) {
+        if (mComponentName == null) {
+            if (other.mComponentName != null) {
                 return false;
             }
-        } else if (!mId.equals(other.mId)) {
+        } else if (!mComponentName.equals(other.mComponentName)) {
             return false;
         }
         return true;
@@ -777,7 +784,7 @@
         stringBuilder.append(", ");
         appendFlags(stringBuilder, flags);
         stringBuilder.append(", ");
-        stringBuilder.append("id: ").append(mId);
+        stringBuilder.append("id: ").append(getId());
         stringBuilder.append(", ");
         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
         stringBuilder.append(", ");
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8185818..b27fa24 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -286,46 +286,31 @@
 
     /**
      * Account visibility was not set.
-     * @hide
      */
     public static final int VISIBILITY_UNDEFINED = 0;
 
     /**
      * Account is always visible to given application and only authenticator can revoke visibility.
-     * @hide
      */
     public static final int VISIBILITY_VISIBLE = 1;
 
     /**
      * Account is visible to given application, but user can revoke visibility.
-     * @hide
      */
     public static final int VISIBILITY_USER_MANAGED_VISIBLE = 2;
 
     /**
      * Account is not visible to given application and only authenticator can grant visibility.
-     * @hide
      */
     public static final int VISIBILITY_NOT_VISIBLE = 3;
 
     /**
      * Account is not visible to given application, but user can reveal it, for example, using
      * {@link #newChooseAccountIntent(Account, List, String[], String, String, String[], Bundle)}
-     * @hide
      */
     public static final int VISIBILITY_USER_MANAGED_NOT_VISIBLE = 4;
 
     /**
-     * Key to manifest entry with a list of account types in which application is interested.
-     * Example value: "com.google;com.customtype". If it is  specified then the application
-     * will only get notifications related to the types in the list (see
-     * {@link #ACTION_VISIBLE_ACCOUNTS_CHANGED}). Authenticators managing whitelisted types will be
-     * able to know about the application using {@link #ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED}
-     * @hide
-     */
-    public static final String SUPPORTED_ACCOUNT_TYPES = "android.accounts.SupportedAccountTypes";
-
-    /**
      * Token type for the special case where a UID has access only to an account
      * but no authenticator specific auth token types.
      *
@@ -344,48 +329,27 @@
      *
      * @see #addOnAccountsUpdatedListener
      *
-     * Deprecated - use ACTION_VISIBLE_ACCOUNTS_CHANGED instead.
+     * @deprecated use #addOnAccountsUpdatedListener to get account updates in runtime.
      */
     public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
         "android.accounts.LOGIN_ACCOUNTS_CHANGED";
 
     /**
-     * Action sent as a broadcast Intent by the AccountsService when accounts potentially visible to
-     * the applications are added, accounts are removed, or an account's credentials (saved
-     * password, etc) are changed. List of supported account types shoud be specified in the
-     * Manifest file using {@link #SUPPORTED_ACCOUNT_TYPES}
-     *
-     * @see #addOnAccountsUpdatedListener
-     * @hide
-     */
-    public static final String ACTION_VISIBLE_ACCOUNTS_CHANGED =
-            "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
-
-    /**
-     * Authenticators may subscribe to get notifications about apps interested in their managed account
-     * types using {@link #SUPPORTED_ACCOUNT_TYPES}.
-     * @hide
-     */
-    public static final String ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED =
-            "android.accounts.action.ACCOUNTS_LISTENER_PACKAGE_INSTALLED";
-
-    /**
      * Uid key to set default visibility for applications targeting API level
-     * {@link android.os.Build.VERSION_CODES#O} or above. See {@link #getAccountVisibility}. If the
-     * value was not set by authenticator USER_MANAGED_NOT_VISIBLE is used.
-     * @hide
+     * {@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.
      */
-    public static final int DEFAULT_VISIBILITY = -2;
+    public static final int UID_KEY_DEFAULT_VISIBILITY = -2;
 
     /**
      * Uid key to set visibility for applications targeting API level below
-     * {@link android.os.Build.VERSION_CODES#O}, which were able to see the account before. It
-     * includes applications with GET_ACCOUNTS permission or with the same signature as
-     * authenticator. See {@link #getAccountVisibility}. If the value was not set by authenticator
-     * USER_MANAGED_VISIBLE is used.
-     * @hide
+     * {@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.
      */
-    public static final int DEFAULT_LEGACY_VISIBILITY = -3;
+    public static final int UID_KEY_DEFAULT_LEGACY_VISIBILITY = -3;
 
     /**
      * @hide
@@ -874,43 +838,11 @@
      * @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 selectedUids Array of uids whose associated applications can access this account
-     *        without any additional user approval.
-     *
-     * @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,
-            int[] selectedUids) {
-        return false; // TODO remove this method.
-    }
-
-    /**
-     * 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.
-     * <p>
-     * Normally used by sign-up wizards associated with authenticators, not directly by
-     * applications.
-     * <p>
-     * Calling this method does not update the last authenticated timestamp, referred by
-     * {@link #KEY_LAST_AUTHENTICATED_TIME}. To update it, call
-     * {@link #notifyAccountAuthenticated(Account)} after getting success.
-     * <p>
-     * It is safe to call this method from the main thread.
-     * <p>
-     * This method requires the caller to have a signature match with the authenticator that owns
-     * the specified account.
-     *
-     * @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.
      *
      * @return True if the account was successfully added, false if the account already exists, the
      *         account is null, or another error occurs.
-     * @hide
      */
     public boolean addAccountExplicitly(Account account, String password, Bundle extras,
             Map<Integer, Integer> visibility) {
@@ -925,22 +857,18 @@
     }
 
     /**
-     * Returns all UIDs for applications that requested the account type.
-     * <p>This method requires the caller to have a signature match with the authenticator
-     * that owns the specified account.
+     * Returns UIDs of applications for which visibility of given account was explicitly set.
+     * <p>
+     * This method requires the caller to have a signature match with the authenticator that owns
+     * the specified account.
      *
-     * @param accountType The account type to be authenticated.
+     * @param account The account for which visibility data should be returned.
      *
-     * @return array of all UIDs that support accounts of this
-     * account type that seek approval (to be used to know which accounts for
-     * the authenticator to include in addAccountExplicitly). Null if none.
+     * @return Map from uid to visibility for given account
      */
-    public int[] getRequestingUidsForType(String accountType) {
-        try {
-            return mService.getRequestingUidsForType(accountType);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
+    public Map<Integer, Integer> getUidsAndVisibilityForAccount(Account account) {
+        // TODO implement.
+        return null;
     }
 
     /**
@@ -954,9 +882,8 @@
      * @param packageName Package name.
      * @param accountType Account type.
      *
-     * @return Map with visibility for all accounts of given type. See {@link #getAccountVisibility}
-     *         for possilbe values.
-     * @hide
+     * @return Map with visibility for all accounts of given type.
+     * See {@link #getAccountVisibility} for possilbe values.
      */
     public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
             String accountType) {
@@ -971,67 +898,6 @@
     }
 
     /**
-     * Gives a certain UID, represented a application, access to an account
-     * <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 add account access.
-     *
-     * @return True if account made visible to application and was not previously visible.
-     */
-    public boolean makeAccountVisible(Account account, int uid) {
-        try {
-            return mService.setAccountVisibility(account, uid, VISIBILITY_USER_MANAGED_VISIBLE);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Removes visibility of certain account of a process identified by a given UID to an
-     * application. This is called by the Authenticator.
-     * <p>
-     * This method requires the caller to have a signature match with the authenticator that owns
-     * the specified account.
-     *
-     * @param account Remove visibility of this account..
-     * @param uid The UID of the application to remove account access.
-     *
-     * @return True if application access to account removed and was previously visible.
-     */
-    public boolean removeAccountVisibility(Account account, int uid) {
-        try {
-            return mService.setAccountVisibility(account, uid, VISIBILITY_USER_MANAGED_NOT_VISIBLE);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Checks visibility of certain account of a process identified by a given UID. This is called
-     * by the Authenticator.
-     * <p>
-     * This method requires the caller to have a signature match with the authenticator that owns
-     * the specified account.
-     *
-     * @param account Account to check visibility.
-     * @param uid The UID of the application to check account access.
-     *
-     * @return True if application has access to the account
-     */
-    public boolean isAccountVisible(Account account, int uid) {
-        try {
-            Integer visibility = mService.getAccountVisibility(account, uid);
-            return visibility == VISIBILITY_USER_MANAGED_NOT_VISIBLE
-                    || visibility == VISIBILITY_VISIBLE;
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Set visibility value of given account to certain UID.
      * <p>
      * See {@link #getAccountVisibility} for possible values.
@@ -1044,7 +910,6 @@
      * @param visibility - new visibility value.
      *
      * @return True if visibility value was succesfully updated.
-     * @hide
      */
     public boolean setAccountVisibility(Account account, int uid,
             @AccountVisibility int visibility) {
@@ -1058,6 +923,7 @@
     /**
      * Gets visibility of certain account for given UID. Possible returned values are:
      * <ul>
+     * <li>{@link #VISIBILITY_UNDEFINED}</li>
      * <li>{@link #VISIBILITY_VISIBLE}</li>
      * <li>{@link #VISIBILITY_USER_MANAGED_VISIBLE}</li>
      * <li>{@link #VISIBILITY_NOT_VISIBLE}
@@ -1072,7 +938,6 @@
      * @param uid The UID of the application to get account visibility.
      *
      * @return int Visibility for given account and uid.
-     * @hide
      */
     public @AccountVisibility int getAccountVisibility(Account account, int uid) {
         try {
@@ -2916,20 +2781,29 @@
     /**
      * Adds an {@link OnAccountsUpdateListener} to this instance of the {@link AccountManager}. This
      * listener will be notified whenever user or AbstractAcccountAuthenticator made changes to
-     * accounts related to the caller - either list of accounts returned by {@link #getAccounts()}
-     * was changed, or new account was added for which user can grant access to the caller.
+     * accounts of any type related to the caller. This method is equivalent to
+     * addOnAccountsUpdatedListener(listener, handler, updateImmediately, null)
      *
+     * @see #addOnAccountsUpdatedListener(OnAccountsUpdateListener, Handler, boolean, Handler,
+     *      String[])
+     */
+    public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
+            Handler handler, boolean updateImmediately) {
+        addOnAccountsUpdatedListener(listener, handler,updateImmediately, null);
+    }
+
+    /**
+     * Adds an {@link OnAccountsUpdateListener} to this instance of the {@link AccountManager}. This
+     * listener will be notified whenever user or AbstractAcccountAuthenticator made changes to
+     * accounts of given types related to the caller -
+     * either list of accounts returned by {@link #getAccounts()}
+     * was changed, or new account was added for which user can grant access to the caller.
      * <p>
      * As long as this listener is present, the AccountManager instance will not be
      * garbage-collected, and neither will the {@link Context} used to retrieve it, which may be a
      * large Activity instance. To avoid memory leaks, you must remove this listener before then.
      * Normally listeners are added in an Activity or Service's {@link Activity#onCreate} and
      * removed in {@link Activity#onDestroy}.
-     *
-     *
-     * If SUPPORTED_ACCOUNT_TYPES is specified in the manifest file, listener will only be
-     * notified about whitelisted types.
-     *
      * <p>
      * It is safe to call this method from the main thread.
      *
@@ -2938,11 +2812,12 @@
      *        main thread
      * @param updateImmediately If true, the listener will be invoked (on the handler thread) right
      *        away with the current account list
+     * @param accountTypes If set, only changes to accounts of given types will be reported.
      * @throws IllegalArgumentException if listener is null
      * @throws IllegalStateException if listener was already added
      */
     public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
-            Handler handler, boolean updateImmediately) {
+            Handler handler, boolean updateImmediately, String[] accountTypes) {
         if (listener == null) {
             throw new IllegalArgumentException("the listener is null");
         }
@@ -2958,11 +2833,11 @@
             if (wasEmpty) {
                 // Register a broadcast receiver to monitor account changes
                 IntentFilter intentFilter = new IntentFilter();
-                if (isVisibleAccountsChangedBroadcastSupported()) {
-                    intentFilter.addAction(ACTION_VISIBLE_ACCOUNTS_CHANGED);
-                } else {
-                    intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
-                }
+                // TODO get rid of the broadcast receiver
+                // create android.os.ResultReceiver
+                // send it to the service via aidl
+                // handle onReceiveResult
+                intentFilter.addAction(LOGIN_ACCOUNTS_CHANGED_ACTION);
                 // To recover from disk-full.
                 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
                 // Register a broadcast receiver to monitor account changes
@@ -2975,26 +2850,6 @@
     }
 
     /**
-     * @hide
-     */
-    private boolean isVisibleAccountsChangedBroadcastSupported() {
-        String interestedTypes = null;
-        try {
-            String packageName = mContext.getOpPackageName();
-            ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA);
-            Bundle b = ai.metaData;
-            if (b == null) {
-                return false;
-            }
-            interestedTypes = b.getString(SUPPORTED_ACCOUNT_TYPES);
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-        return !TextUtils.isEmpty(interestedTypes);
-    }
-
-    /**
      * Removes an {@link OnAccountsUpdateListener} previously registered with
      * {@link #addOnAccountsUpdatedListener}.  The listener will no longer
      * receive notifications of account changes.
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f6771857..a9d1cf6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -78,8 +78,6 @@
 import android.service.autofill.IAutoFillAppCallback;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
-import android.text.TextAssistant;
-import android.text.TextClassificationManager;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
 import android.transition.Scene;
@@ -792,8 +790,6 @@
 
     private VoiceInteractor mVoiceInteractor;
 
-    private TextAssistant mTextAssistant;
-
     private CharSequence mTitle;
     private int mTitleColor = 0;
 
@@ -1398,24 +1394,6 @@
     }
 
     /**
-     * Sets the default {@link TextAssistant} for {@link android.widget.TextView}s in this Activity.
-     */
-    public void setTextAssistant(TextAssistant textAssistant) {
-        mTextAssistant = textAssistant;
-    }
-
-    /**
-     * Returns the default {@link TextAssistant} for {@link android.widget.TextView}s
-     * in this Activity.
-     */
-    public TextAssistant getTextAssistant() {
-        if (mTextAssistant != null) {
-            return mTextAssistant;
-        }
-        return getSystemService(TextClassificationManager.class);
-    }
-
-    /**
      * This is called for activities that set launchMode to "singleTop" in
      * their package, or if a client used the {@link Intent#FLAG_ACTIVITY_SINGLE_TOP}
      * flag when calling {@link #startActivity}.  In either case, when the
@@ -2029,78 +2007,53 @@
     }
 
     /**
-     * Puts the activity in picture-in-picture mode.
+     * Puts the activity in picture-in-picture mode if possible in the current system state. Any
+     * prior calls to {@link #setPictureInPictureArgs(PictureInPictureArgs)} will still apply when
+     * entering picture-in-picture through this call.
+     *
+     * @see #enterPictureInPictureMode(PictureInPictureArgs)
      * @see android.R.attr#supportsPictureInPicture
      */
     public void enterPictureInPictureMode() {
-        try {
-            ActivityManager.getService().enterPictureInPictureMode(mToken);
-        } catch (RemoteException e) {
-        }
+        enterPictureInPictureMode(new PictureInPictureArgs());
     }
 
     /**
-     * Puts the activity in picture-in-picture mode with a given aspect ratio.
+     * Puts the activity in picture-in-picture mode if possible in the current system state with
+     * explicit given arguments. Only the set parameters in {@param args} will override prior calls
+     * {@link #setPictureInPictureArgs(PictureInPictureArgs)}.
+     *
+     * The system may disallow entering picture-in-picture in various cases, including when the
+     * activity is not visible.
+     *
      * @see android.R.attr#supportsPictureInPicture
      *
-     * @param aspectRatio the new aspect ratio of the picture-in-picture.
+     * @param args the explicit non-null arguments to use when entering picture-in-picture.
+     * @return whether the system successfully entered picture-in-picture.
      */
-    public void enterPictureInPictureMode(float aspectRatio) {
+    public boolean enterPictureInPictureMode(@NonNull PictureInPictureArgs args) {
         try {
-            ActivityManagerNative.getDefault().enterPictureInPictureModeWithAspectRatio(mToken,
-                    aspectRatio);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Requests to the system that the activity can be automatically put into picture-in-picture
-     * mode when the user leaves the activity causing it normally to be hidden.  Generally, this
-     * happens when another task is brought to the forground or the task containing this activity
-     * is moved to the background.  This is a *not* a guarantee that the activity will actually be
-     * put in picture-in-picture mode, and depends on a number of factors, including whether there
-     * is already something in picture-in-picture.
-     *
-     * @param enterPictureInPictureOnMoveToBg whether or not this activity can automatically enter
-     *                                        picture-in-picture
-     */
-    public void enterPictureInPictureModeOnMoveToBackground(
-            boolean enterPictureInPictureOnMoveToBg) {
-        try {
-            ActivityManagerNative.getDefault().enterPictureInPictureModeOnMoveToBackground(mToken,
-                    enterPictureInPictureOnMoveToBg);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Updates the aspect ratio of the current picture-in-picture activity if this activity is
-     * already in picture-in-picture mode, or sets it to be used later if
-     * {@link #enterPictureInPictureModeOnMoveToBackground(boolean)} is requested.
-     *
-     * @param aspectRatio the new aspect ratio of the picture-in-picture.
-     */
-    public void setPictureInPictureAspectRatio(float aspectRatio) {
-        try {
-            ActivityManagerNative.getDefault().setPictureInPictureAspectRatio(mToken, aspectRatio);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * Updates the set of user actions associated with the picture-in-picture activity.
-     *
-     * @param actions the new actions for picture-in-picture (can be null to reset the set of
-     *                actions).  The maximum number of actions that will be displayed on this device
-     *                is defined by {@link ActivityManager#getMaxNumPictureInPictureActions()}.
-     */
-    public void setPictureInPictureActions(List<RemoteAction> actions) {
-        try {
-            if (actions == null) {
-                actions = new ArrayList<>();
+            if (args == null) {
+                throw new IllegalArgumentException("Expected non-null picture-in-picture args");
             }
-            ActivityManagerNative.getDefault().setPictureInPictureActions(mToken,
-                    new ParceledListSlice<RemoteAction>(actions));
+            return ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken, args);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Updates the properties of the picture-in-picture activity, or sets it to be used later when
+     * {@link #enterPictureInPictureMode()} is called.
+     *
+     * @param args the new properties of the picture-in-picture.
+     */
+    public void setPictureInPictureArgs(@NonNull PictureInPictureArgs args) {
+        try {
+            if (args == null) {
+                throw new IllegalArgumentException("Expected non-null picture-in-picture args");
+            }
+            ActivityManagerNative.getDefault().setPictureInPictureArgs(mToken, args);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f1f6e7b..c1a888d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -520,15 +520,19 @@
     /** @hide Flag for registerUidObserver: report uid has become active. */
     public static final int UID_OBSERVER_ACTIVE = 1<<3;
 
-    /** @hide Mode for {@link IActivityManager#getAppStartMode}: normal free-to-run operation. */
+    /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. */
     public static final int APP_START_MODE_NORMAL = 0;
 
-    /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later. */
+    /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later. */
     public static final int APP_START_MODE_DELAYED = 1;
 
-    /** @hide Mode for {@link IActivityManager#getAppStartMode}: disable/cancel pending
-     * launches. */
-    public static final int APP_START_MODE_DISABLED = 2;
+    /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later, with
+     * rigid errors (throwing exception). */
+    public static final int APP_START_MODE_DELAYED_RIGID = 2;
+
+    /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: disable/cancel pending
+     * launches; this is the mode for ephemeral apps. */
+    public static final int APP_START_MODE_DISABLED = 3;
 
     /**
      * Lock task mode is not active.
@@ -2176,6 +2180,12 @@
             dest.writeParcelable(mContentInsets, 0);
         }
 
+        @Override
+        public String toString() {
+            return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation
+                    + " mContentInsets=" + mContentInsets.toShortString();
+        }
+
         public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
             public TaskSnapshot createFromParcel(Parcel source) {
                 return new TaskSnapshot(source);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 87700dc..89510d9 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -64,36 +64,6 @@
     public static final int APP_TRANSITION_TIMEOUT = 3;
 
     /**
-     * Class to hold deferred properties to apply for picture-in-picture for a given activity.
-     */
-    public static class PictureInPictureArguments {
-        /**
-         * The expected aspect ratio of the picture-in-picture.
-         */
-        public float aspectRatio;
-
-        /**
-         * The set of actions that are associated with this activity when in picture in picture.
-         */
-        public List<RemoteAction> userActions = new ArrayList<>();
-
-        public void dump(PrintWriter pw, String prefix) {
-            pw.println(prefix + "aspectRatio=" + aspectRatio);
-            if (userActions.isEmpty()) {
-                pw.println(prefix + "  userActions=[]");
-            } else {
-                pw.println(prefix + "  userActions=[");
-                for (int i = 0; i < userActions.size(); i++) {
-                    RemoteAction action = userActions.get(i);
-                    pw.print(prefix + "    Action[" + i + "]: ");
-                    action.dump("", pw);
-                }
-                pw.println(prefix + "  ]");
-            }
-        }
-    }
-
-    /**
      * Grant Uri permissions from one app to another. This method only extends
      * permission grants if {@code callingUid} has permission to them.
      */
@@ -201,6 +171,17 @@
     public abstract void setPendingIntentWhitelistDuration(IIntentSender target, long duration);
 
     /**
+     * Allow DeviceIdleController to tell us about what apps are whitelisted.
+     */
+    public abstract void setDeviceIdleWhitelist(int[] appids);
+
+    /**
+     * Update information about which app IDs are on the temp whitelist.
+     */
+    public abstract void updateDeviceIdleTempWhitelist(int[] appids, int changingAppId,
+            boolean adding);
+
+    /**
      * Updates and persists the {@link Configuration} for a given user.
      *
      * @param values the configuration to update
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0b3ae3a..d814ddc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -245,7 +245,7 @@
     boolean mSomeActivitiesChanged = false;
     boolean mUpdatingSystemConfig = false;
 
-    // These can be accessed by multiple threads; mPackages is the lock.
+    // These can be accessed by multiple threads; mResourcesManager is the lock.
     // XXX For now we keep around information about all packages we have
     // seen, not removing entries from this map.
     // NOTE: The activity and window managers need to call in to
@@ -254,12 +254,13 @@
     // holds their own lock.  Thus you MUST NEVER call back into the activity manager
     // or window manager or anything that depends on them while holding this lock.
     // These LoadedApk are only valid for the userId that we're running as.
-    final ArrayMap<String, WeakReference<LoadedApk>> mPackages
-            = new ArrayMap<String, WeakReference<LoadedApk>>();
-    final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages
-            = new ArrayMap<String, WeakReference<LoadedApk>>();
-    final ArrayList<ActivityClientRecord> mRelaunchingActivities
-            = new ArrayList<ActivityClientRecord>();
+    @GuardedBy("mResourcesManager")
+    final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
+    @GuardedBy("mResourcesManager")
+    final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages = new ArrayMap<>();
+    @GuardedBy("mResourcesManager")
+    final ArrayList<ActivityClientRecord> mRelaunchingActivities = new ArrayList<>();
+    @GuardedBy("mResourcesManager")
     Configuration mPendingConfiguration = null;
     // Because we merge activity relaunch operations we can't depend on the ordering provided by
     // the handler messages. We need to introduce secondary ordering mechanism, which will allow
@@ -904,6 +905,10 @@
             sendMessage(H.CONFIGURATION_CHANGED, config);
         }
 
+        public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
+            sendMessage(H.APPLICATION_INFO_CHANGED, ai);
+        }
+
         public void updateTimeZone() {
             TimeZone.setDefault(null);
         }
@@ -1448,6 +1453,7 @@
         public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
         public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
         public static final int ATTACH_AGENT = 155;
+        public static final int APPLICATION_INFO_CHANGED = 156;
 
         String codeToString(int code) {
             if (DEBUG_MESSAGES) {
@@ -1505,6 +1511,7 @@
                     case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
                     case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
                     case ATTACH_AGENT: return "ATTACH_AGENT";
+                    case APPLICATION_INFO_CHANGED: return "APPLICATION_INFO_CHANGED";
                 }
             }
             return Integer.toString(code);
@@ -1636,8 +1643,11 @@
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
                     mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
                     mUpdatingSystemConfig = true;
-                    handleConfigurationChanged((Configuration)msg.obj, null);
-                    mUpdatingSystemConfig = false;
+                    try {
+                        handleConfigurationChanged((Configuration) msg.obj, null);
+                    } finally {
+                        mUpdatingSystemConfig = false;
+                    }
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case CLEAN_UP_CONTEXT:
@@ -1763,6 +1773,14 @@
                 case ATTACH_AGENT:
                     handleAttachAgent((String) msg.obj);
                     break;
+                case APPLICATION_INFO_CHANGED:
+                    mUpdatingSystemConfig = true;
+                    try {
+                        handleApplicationInfoChanged((ApplicationInfo) msg.obj);
+                    } finally {
+                        mUpdatingSystemConfig = false;
+                    }
+                    break;
             }
             Object obj = msg.obj;
             if (obj instanceof SomeArgs) {
@@ -3500,15 +3518,17 @@
                 }
                 r.activity.performResume();
 
-                // If there is a pending local relaunch that was requested when the activity was
-                // paused, it will put the activity into paused state when it finally happens.
-                // Since the activity resumed before being relaunched, we don't want that to happen,
-                // so we need to clear the request to relaunch paused.
-                for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
-                    final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
-                    if (relaunching.token == r.token
-                            && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
-                        relaunching.startsNotResumed = false;
+                synchronized (mResourcesManager) {
+                    // If there is a pending local relaunch that was requested when the activity was
+                    // paused, it will put the activity into paused state when it finally happens.
+                    // Since the activity resumed before being relaunched, we don't want that to
+                    // happen, so we need to clear the request to relaunch paused.
+                    for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
+                        final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
+                        if (relaunching.token == r.token
+                                && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
+                            relaunching.startsNotResumed = false;
+                        }
                     }
                 }
 
@@ -4898,6 +4918,53 @@
         }
     }
 
+    void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
+        // Updates triggered by package installation go through a package update
+        // receiver. Here we try to capture ApplicationInfo changes that are
+        // caused by other sources, such as overlays. That means we want to be as conservative
+        // about code changes as possible. Take the diff of the old ApplicationInfo and the new
+        // to see if anything needs to change.
+        synchronized (mResourcesManager) {
+            // Update all affected loaded packages with new package information
+            WeakReference<LoadedApk> ref = mPackages.get(ai.packageName);
+            LoadedApk apk = ref != null ? ref.get() : null;
+            if (apk != null) {
+                final ArrayList<String> oldPaths = new ArrayList<>();
+                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths, null /*outLibPaths*/);
+                apk.updateApplicationInfo(ai, oldPaths);
+            }
+
+            ref = mResourcePackages.get(ai.packageName);
+            apk = ref != null ? ref.get() : null;
+            if (apk != null) {
+                final ArrayList<String> oldPaths = new ArrayList<>();
+                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths, null /*outLibPaths*/);
+                apk.updateApplicationInfo(ai, oldPaths);
+            }
+
+            // Update all affected Resources objects to use new ResourcesImpl
+            mResourcesManager.applyNewResourceDirsLocked(ai.sourceDir, ai.resourceDirs);
+        }
+
+        ApplicationPackageManager.configurationChanged();
+
+        // Trigger a regular Configuration change event, only with a different assetsSeq number
+        // so that we actually call through to all components.
+        Configuration newConfig = new Configuration();
+        newConfig.unset();
+        newConfig.assetsSeq = mConfiguration.assetsSeq + 1;
+        handleConfigurationChanged(newConfig, null);
+
+        // Schedule all activities to reload
+        for (final Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
+            final Activity activity = entry.getValue().activity;
+            if (!activity.mFinished) {
+                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
+                        false);
+            }
+        }
+    }
+
     static void freeTextLayoutCachesIfNeeded(int configDiff) {
         if (configDiff != 0) {
             // Ask text layout engine to free its caches if there is a locale change
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 67fbc5a..9cc13ab 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -243,8 +243,10 @@
     public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
     /** @hide Read the phone number. */
     public static final int OP_READ_PHONE_NUMBER = 65;
+    /** @hide Request package installs through package installer */
+    public static final int OP_REQUEST_INSTALL_PACKAGES = 66;
     /** @hide */
-    public static final int _NUM_OP = 66;
+    public static final int _NUM_OP = 67;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -461,6 +463,7 @@
             OP_RUN_IN_BACKGROUND,
             OP_AUDIO_ACCESSIBILITY_VOLUME,
             OP_READ_PHONE_NUMBER,
+            OP_REQUEST_INSTALL_PACKAGES,
     };
 
     /**
@@ -534,6 +537,7 @@
             null,
             null, // OP_AUDIO_ACCESSIBILITY_VOLUME
             OPSTR_READ_PHONE_NUMBER,
+            null, // OP_REQUEST_INSTALL_PACKAGES
     };
 
     /**
@@ -607,6 +611,7 @@
             "RUN_IN_BACKGROUND",
             "AUDIO_ACCESSIBILITY_VOLUME",
             "READ_PHONE_NUMBER",
+            "REQUEST_INSTALL_PACKAGES",
     };
 
     /**
@@ -680,6 +685,7 @@
             null, // no permission for running in background
             null, // no permission for changing accessibility volume
             Manifest.permission.READ_PHONE_NUMBER,
+            Manifest.permission.REQUEST_INSTALL_PACKAGES,
     };
 
     /**
@@ -754,6 +760,7 @@
             null, // RUN_IN_BACKGROUND
             UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME
             null, // READ_PHONE_NUMBER
+            null, // REQUEST_INSTALL_PACKAGES
     };
 
     /**
@@ -827,6 +834,7 @@
             false, // RUN_IN_BACKGROUND
             false, // AUDIO_ACCESSIBILITY_VOLUME
             false, // READ_PHONE_NUMBER
+            false, // REQUEST_INSTALL_PACKAGES
     };
 
     /**
@@ -899,6 +907,7 @@
             AppOpsManager.MODE_ALLOWED,  // OP_RUN_IN_BACKGROUND
             AppOpsManager.MODE_ALLOWED,  // OP_AUDIO_ACCESSIBILITY_VOLUME
             AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES
     };
 
     /**
@@ -975,6 +984,7 @@
             false,
             false, // OP_AUDIO_ACCESSIBILITY_VOLUME
             false,
+            false, // OP_REQUEST_INSTALL_PACKAGES
     };
 
     /**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f3185a8..f790542 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -17,13 +17,14 @@
 package android.app;
 
 import android.annotation.DrawableRes;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.XmlRes;
-import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
@@ -52,13 +53,13 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.VersionedPackage;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -136,6 +137,21 @@
     }
 
     @Override
+    public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int flags)
+            throws NameNotFoundException {
+        try {
+            PackageInfo pi = mPM.getPackageInfoVersioned(versionedPackage, flags,
+                    mContext.getUserId());
+            if (pi != null) {
+                return pi;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        throw new NameNotFoundException(versionedPackage.toString());
+    }
+
+    @Override
     public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
             throws NameNotFoundException {
         try {
@@ -146,7 +162,6 @@
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-
         throw new NameNotFoundException(packageName);
     }
 
@@ -444,6 +459,28 @@
 
     /** @hide */
     @Override
+    public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) {
+        return getSharedLibrariesAsUser(flags, mContext.getUserId());
+    }
+
+    /** @hide */
+    @Override
+    @SuppressWarnings("unchecked")
+    public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) {
+        try {
+            ParceledListSlice<SharedLibraryInfo> sharedLibs = mPM.getSharedLibraries(
+                    flags, userId);
+            if (sharedLibs == null) {
+                return Collections.emptyList();
+            }
+            return sharedLibs.getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    @Override
     public @NonNull String getServicesSystemSharedLibraryPackageName() {
         try {
             return mPM.getServicesSystemSharedLibraryPackageName();
@@ -1386,7 +1423,7 @@
         }
     }
 
-    ApplicationPackageManager(ContextImpl context,
+    protected ApplicationPackageManager(ContextImpl context,
                               IPackageManager pm) {
         mContext = context;
         mPM = pm;
@@ -1820,6 +1857,12 @@
     @Override
     public @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app) {
         final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        return getPackageCurrentVolume(app, storage);
+    }
+
+    @VisibleForTesting
+    protected @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app,
+            StorageManager storage) {
         if (app.isInternal()) {
             return storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
         } else if (app.isExternalAsec()) {
@@ -1831,25 +1874,43 @@
 
     @Override
     public @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app) {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
-        final VolumeInfo currentVol = getPackageCurrentVolume(app);
-        final List<VolumeInfo> vols = storage.getVolumes();
+        final StorageManager storageManager = mContext.getSystemService(StorageManager.class);
+        return getPackageCandidateVolumes(app, storageManager, mPM);
+    }
+
+    @VisibleForTesting
+    protected @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app,
+            StorageManager storageManager, IPackageManager pm) {
+        final VolumeInfo currentVol = getPackageCurrentVolume(app, storageManager);
+        final List<VolumeInfo> vols = storageManager.getVolumes();
         final List<VolumeInfo> candidates = new ArrayList<>();
         for (VolumeInfo vol : vols) {
-            if (Objects.equals(vol, currentVol) || isPackageCandidateVolume(mContext, app, vol)) {
+            if (Objects.equals(vol, currentVol)
+                    || isPackageCandidateVolume(mContext, app, vol, pm)) {
                 candidates.add(vol);
             }
         }
         return candidates;
     }
 
-    private boolean isPackageCandidateVolume(
-            ContextImpl context, ApplicationInfo app, VolumeInfo vol) {
-        final boolean forceAllowOnExternal = Settings.Global.getInt(
+    @VisibleForTesting
+    protected boolean isForceAllowOnExternal(Context context) {
+        return Settings.Global.getInt(
                 context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
-        // Private internal is always an option
+    }
+
+    @VisibleForTesting
+    protected boolean isAllow3rdPartyOnInternal(Context context) {
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+    }
+
+    private boolean isPackageCandidateVolume(
+            ContextImpl context, ApplicationInfo app, VolumeInfo vol, IPackageManager pm) {
+        final boolean forceAllowOnExternal = isForceAllowOnExternal(context);
+
         if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) {
-            return true;
+            return app.isSystemApp() || isAllow3rdPartyOnInternal(context);
         }
 
         // System apps and apps demanding internal storage can't be moved
@@ -1875,7 +1936,7 @@
 
         // Some apps can't be moved. (e.g. device admins)
         try {
-            if (mPM.isPackageDeviceAdminOnAnyUser(app.packageName)) {
+            if (pm.isPackageDeviceAdminOnAnyUser(app.packageName)) {
                 return false;
             }
         } catch (RemoteException e) {
@@ -1952,10 +2013,11 @@
     }
 
     @Override
-    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
-            int userId) {
+    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
+            int flags, int userId) {
         try {
-            mPM.deletePackageAsUser(packageName, observer, userId, flags);
+            mPM.deletePackageAsUser(packageName, PackageManager.VERSION_CODE_HIGHEST,
+                    observer, userId, flags);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2278,7 +2340,7 @@
         synchronized (mLock) {
             if (mInstaller == null) {
                 try {
-                    mInstaller = new PackageInstaller(mContext, this, mPM.getPackageInstaller(),
+                    mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
                             mContext.getPackageName(), mContext.getUserId());
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d08bee5..d37888d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -1342,8 +1341,8 @@
         }
         try {
             final Intent intent = ActivityManager.getService().registerReceiver(
-                    mMainThread.getApplicationThread(), mBasePackageName,
-                    rd, filter, broadcastPermission, userId);
+                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
+                    broadcastPermission, userId);
             if (intent != null) {
                 intent.setExtrasClassLoader(getClassLoader());
                 intent.prepareToEnterProcess();
@@ -1385,7 +1384,14 @@
     @Override
     public ComponentName startService(Intent service) {
         warnIfCallingFromSystemProcess();
-        return startServiceCommon(service, mUser);
+        return startServiceCommon(service, -1, null, mUser);
+    }
+
+    @Override
+    public ComponentName startServiceInForeground(Intent service,
+            int id, Notification notification) {
+        warnIfCallingFromSystemProcess();
+        return startServiceCommon(service, id, notification, mUser);
     }
 
     @Override
@@ -1396,16 +1402,24 @@
 
     @Override
     public ComponentName startServiceAsUser(Intent service, UserHandle user) {
-        return startServiceCommon(service, user);
+        return startServiceCommon(service, -1, null, user);
     }
 
-    private ComponentName startServiceCommon(Intent service, UserHandle user) {
+    @Override
+    public ComponentName startServiceInForegroundAsUser(Intent service,
+            int id, Notification notification, UserHandle user) {
+        return startServiceCommon(service, id, notification, user);
+    }
+
+    private ComponentName startServiceCommon(Intent service, int id, Notification notification,
+            UserHandle user) {
         try {
             validateServiceIntent(service);
             service.prepareToLeaveProcess(this);
             ComponentName cn = ActivityManager.getService().startService(
                 mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
-                            getContentResolver()), getOpPackageName(), user.getIdentifier());
+                            getContentResolver()), id, notification, getOpPackageName(),
+                            user.getIdentifier());
             if (cn != null) {
                 if (cn.getPackageName().equals("!")) {
                     throw new SecurityException(
@@ -1415,6 +1429,9 @@
                     throw new SecurityException(
                             "Unable to start service " + service
                             + ": " + cn.getClassName());
+                } else if (cn.getPackageName().equals("?")) {
+                    throw new IllegalStateException(
+                            "Not allowed to start service " + service + ": " + cn.getClassName());
                 }
             }
             return cn;
@@ -1573,9 +1590,20 @@
             throw new IllegalArgumentException("permission is null");
         }
 
+        final IActivityManager am = ActivityManager.getService();
+        if (am == null) {
+            // Well this is super awkward; we somehow don't have an active
+            // ActivityManager instance. If we're testing a root or system
+            // UID, then they totally have whatever permission this is.
+            final int appId = UserHandle.getAppId(uid);
+            if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
+                Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission);
+                return PackageManager.PERMISSION_GRANTED;
+            }
+        }
+
         try {
-            return ActivityManager.getService().checkPermission(
-                    permission, pid, uid);
+            return am.checkPermission(permission, pid, uid);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 10ab2bc..62d6898 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -102,15 +102,19 @@
         mSavedFragmentState = in.readBundle();
     }
 
-    public Fragment instantiate(FragmentHostCallback host, Fragment parent,
-            FragmentManagerNonConfig childNonConfig) {
+    public Fragment instantiate(FragmentHostCallback host, FragmentContainer container,
+            Fragment parent, FragmentManagerNonConfig childNonConfig) {
         if (mInstance == null) {
             final Context context = host.getContext();
             if (mArguments != null) {
                 mArguments.setClassLoader(context.getClassLoader());
             }
 
-            mInstance = Fragment.instantiate(context, mClassName, mArguments);
+            if (container != null) {
+                mInstance = container.instantiate(context, mClassName, mArguments);
+            } else {
+                mInstance = Fragment.instantiate(context, mClassName, mArguments);
+            }
 
             if (mSavedFragmentState != null) {
                 mSavedFragmentState.setClassLoader(context.getClassLoader());
diff --git a/core/java/android/app/FragmentContainer.java b/core/java/android/app/FragmentContainer.java
index b2e0300..6ed54dc 100644
--- a/core/java/android/app/FragmentContainer.java
+++ b/core/java/android/app/FragmentContainer.java
@@ -18,6 +18,8 @@
 
 import android.annotation.IdRes;
 import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Bundle;
 import android.view.View;
 
 /**
@@ -35,4 +37,13 @@
      * Return {@code true} if the container holds any view.
      */
     public abstract boolean onHasView();
+
+    /**
+     * Creates an instance of the specified fragment, can be overridden to construct fragments
+     * with dependencies, or change the fragment being constructed. By default just calls
+     * {@link Fragment#instantiate(Context, String, Bundle)}.
+     */
+    public Fragment instantiate(Context context, String className, Bundle arguments) {
+        return Fragment.instantiate(context, className, arguments);
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index efd2b69..44f1322 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1984,11 +1984,13 @@
                 if (startIndex != recordNum) {
                     executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                 }
-                // execute all unoptimized together
-                int optimizeEnd;
-                for (optimizeEnd = recordNum + 1; optimizeEnd < numRecords; optimizeEnd++) {
-                    if (records.get(optimizeEnd).mAllowOptimization) {
-                        break;
+                // execute all unoptimized pop operations together or one add operation
+                int optimizeEnd = recordNum + 1;
+                if (isRecordPop.get(recordNum)) {
+                    while (optimizeEnd < numRecords
+                            && isRecordPop.get(optimizeEnd)
+                            && !records.get(optimizeEnd).mAllowOptimization) {
+                        optimizeEnd++;
                     }
                 }
                 executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
@@ -2651,7 +2653,7 @@
                 if (childNonConfigs != null && i < childNonConfigs.size()) {
                     childNonConfig = childNonConfigs.get(i);
                 }
-                Fragment f = fs.instantiate(mHost, mParent, childNonConfig);
+                Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);
                 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
                 mActive.add(f);
                 // Now that the fragment is instantiated (or came from being
@@ -3270,7 +3272,7 @@
                 + Integer.toHexString(id) + " fname=" + fname
                 + " existing=" + fragment);
         if (fragment == null) {
-            fragment = Fragment.instantiate(context, fname);
+            fragment = mContainer.instantiate(context, fname, null);
             fragment.mFromLayout = true;
             fragment.mFragmentId = id != 0 ? id : containerId;
             fragment.mContainerId = containerId;
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index 6d57cd4..80a5aac 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -188,7 +188,10 @@
     private static void configureTransitionsOptimized(FragmentManagerImpl fragmentManager,
             int containerId, FragmentContainerTransition fragments,
             View nonExistentView, ArrayMap<String, String> nameOverrides) {
-        ViewGroup sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        ViewGroup sceneRoot = null;
+        if (fragmentManager.mContainer.onHasView()) {
+            sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        }
         if (sceneRoot == null) {
             return;
         }
@@ -257,7 +260,10 @@
     private static void configureTransitionsUnoptimized(FragmentManagerImpl fragmentManager,
             int containerId, FragmentContainerTransition fragments,
             View nonExistentView, ArrayMap<String, String> nameOverrides) {
-        ViewGroup sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        ViewGroup sceneRoot = null;
+        if (fragmentManager.mContainer.onHasView()) {
+            sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        }
         if (sceneRoot == null) {
             return;
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 21ae853..5a48793 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -31,10 +31,10 @@
 import android.app.ITaskStackListener;
 import android.app.IUiAutomationConnection;
 import android.app.IUidObserver;
-
 import android.app.IUserSwitchObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.PictureInPictureArgs;
 import android.app.ProfilerInfo;
 import android.app.WaitResult;
 import android.app.assist.AssistContent;
@@ -129,7 +129,8 @@
     void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
     PendingIntent getRunningServiceControlPanel(in ComponentName service);
     ComponentName startService(in IApplicationThread caller, in Intent service,
-            in String resolvedType, in String callingPackage, int userId);
+            in String resolvedType, int id, in Notification notification,
+            in String callingPackage, int userId);
     int stopService(in IApplicationThread caller, in Intent service,
             in String resolvedType, int userId);
     int bindService(in IApplicationThread caller, in IBinder token, in Intent service,
@@ -263,7 +264,7 @@
     boolean isImmersive(in IBinder token);
     void setImmersive(in IBinder token, boolean immersive);
     boolean isTopActivityImmersive();
-    void crashApplication(int uid, int initialPid, in String packageName, in String message);
+    void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
     String getProviderMimeType(in Uri uri, int userId);
     IBinder newUriPermissionOwner(in String name);
     void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg,
@@ -474,18 +475,14 @@
     void suppressResizeConfigChanges(boolean suppress);
     void moveTasksToFullscreenStack(int fromStackId, boolean onTop);
     boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds);
-    int getAppStartMode(int uid, in String packageName);
+    boolean isAppStartModeDisabled(int uid, in String packageName);
     boolean unlockUser(int userid, in byte[] token, in byte[] secret,
             in IProgressListener listener);
     boolean isInMultiWindowMode(in IBinder token);
     boolean isInPictureInPictureMode(in IBinder token);
     void killPackageDependents(in String packageName, int userId);
-    void enterPictureInPictureMode(in IBinder token);
-    void enterPictureInPictureModeWithAspectRatio(in IBinder token, float aspectRatio);
-    void enterPictureInPictureModeOnMoveToBackground(in IBinder token,
-            boolean enterPictureInPictureOnMoveToBg);
-    void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio);
-    void setPictureInPictureActions(in IBinder token, in ParceledListSlice actions);
+    boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureArgs args);
+    void setPictureInPictureArgs(in IBinder token, in PictureInPictureArgs args);
     void activityRelaunched(in IBinder token);
     IBinder getUriPermissionOwnerForActivity(in IBinder activityToken);
     /**
@@ -602,6 +599,8 @@
      */
     ActivityManager.TaskSnapshot getTaskSnapshot(int taskId);
 
+    void scheduleApplicationInfoChanged(in List<String> packageNames, int userId);
+
     // WARNING: when these transactions are updated, check if they are any callers on the native
     // side. If so, make sure they are using the correct transaction ids and arguments.
     // If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 7f168c9..41d1255 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -152,4 +152,5 @@
             IVoiceInteractor voiceInteractor);
     void handleTrustStorageUpdate();
     void attachAgent(String path);
+    void scheduleApplicationInfoChanged(in ApplicationInfo ai);
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 07c21a5..f909af0 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -40,6 +40,7 @@
 {
     void cancelAllNotifications(String pkg, int userId);
 
+    void clearData(String pkg, int uid);
     void enqueueToast(String pkg, ITransientNotification callback, int duration);
     void cancelToast(String pkg, ITransientNotification callback);
     void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
@@ -54,10 +55,10 @@
     void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
     void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
     NotificationChannel getNotificationChannel(String pkg, String channelId);
-    NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId);
+    NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
     void deleteNotificationChannel(String pkg, String channelId);
     ParceledListSlice getNotificationChannels(String pkg);
-    ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid);
+    ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
 
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index ef997c9..5e420c0 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -31,8 +31,10 @@
      * Called whenever IActivityManager.startActivity is called on an activity that is already
      * running in the pinned stack and the activity is not actually started, but the task is either
      * brought to the front or a new Intent is delivered to it.
+     *
+     * @param sourceComponent the component name of the activity that initiated the restart attempt
      */
-    void onPinnedActivityRestartAttempt();
+    void onPinnedActivityRestartAttempt(in ComponentName sourceComponent);
 
     /**
      * Called whenever the pinned stack is done animating a resize.
@@ -102,4 +104,9 @@
      * been locked.
      */
     void onTaskProfileLocked(int taskId, int userId);
+
+    /**
+     * Called when a task snapshot got updated.
+     */
+    void onTaskSnapshotChanged(int taskId, in ActivityManager.TaskSnapshot snapshot);
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index cc7981c..b1bdea1 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -443,6 +443,7 @@
         private final String mClass;
         private final ActivityResult mResult;
         private final boolean mBlock;
+        private final boolean mIgnoreMatchingSpecificIntents;
 
 
         // This is protected by 'Instrumentation.this.mSync'.
@@ -454,7 +455,7 @@
         /**
          * Create a new ActivityMonitor that looks for a particular kind of 
          * intent to be started.
-         *  
+         *
          * @param which The set of intents this monitor is responsible for.
          * @param result A canned result to return if the monitor is hit; can 
          *               be null.
@@ -470,6 +471,7 @@
             mClass = null;
             mResult = result;
             mBlock = block;
+            mIgnoreMatchingSpecificIntents = false;
         }
 
         /**
@@ -491,6 +493,34 @@
             mClass = cls;
             mResult = result;
             mBlock = block;
+            mIgnoreMatchingSpecificIntents = false;
+        }
+
+        /**
+         * Create a new ActivityMonitor that can be used for intercepting any activity to be
+         * started.
+         *
+         * <p> When an activity is started, {@link #onMatchIntent(Intent)} will be called on
+         * instances created using this constructor to see if it is a hit.
+         *
+         * @see #onMatchIntent(Intent)
+         */
+        public ActivityMonitor() {
+            mWhich = null;
+            mClass = null;
+            mResult = null;
+            mBlock = false;
+            mIgnoreMatchingSpecificIntents = true;
+        }
+
+        /**
+         * @return true if this monitor is used for intercepting any started activity by calling
+         *         into {@link #onMatchIntent(Intent)}, false if this monitor is only used
+         *         for specific intents corresponding to the intent filter or activity class
+         *         passed in the constructor.
+         */
+        final boolean ignoreMatchingSpecificIntents() {
+            return mIgnoreMatchingSpecificIntents;
         }
 
         /**
@@ -577,10 +607,31 @@
                 }
             }
         }
-        
+
+        /**
+         * Used for intercepting any started activity.
+         *
+         * <p> A non-null return value here will be considered a hit for this monitor.
+         * By default this will return {@code null} and subclasses can override this to return
+         * a non-null value if the intent needs to be intercepted.
+         *
+         * <p> Whenever a new activity is started, this method will be called on instances created
+         * using {@link #Instrumentation.ActivityMonitor()} to check if there is a match. In case
+         * of a match, the activity start will be blocked and the returned result will be used.
+         *
+         * @param intent The intent used for starting the activity.
+         * @return The {@link ActivityResult} that needs to be used in case of a match.
+         */
+        public ActivityResult onMatchIntent(Intent intent) {
+            return null;
+        }
+
         final boolean match(Context who,
                             Activity activity,
                             Intent intent) {
+            if (mIgnoreMatchingSpecificIntents) {
+                return false;
+            }
             synchronized (this) {
                 if (mWhich != null
                     && mWhich.match(who.getContentResolver(), intent,
@@ -1492,7 +1543,14 @@
                 final int N = mActivityMonitors.size();
                 for (int i=0; i<N; i++) {
                     final ActivityMonitor am = mActivityMonitors.get(i);
-                    if (am.match(who, null, intent)) {
+                    ActivityResult result = null;
+                    if (am.ignoreMatchingSpecificIntents()) {
+                        result = am.onMatchIntent(intent);
+                    }
+                    if (result != null) {
+                        am.mHits++;
+                        return result;
+                    } else if (am.match(who, null, intent)) {
                         am.mHits++;
                         if (am.isBlocking()) {
                             return requestCode >= 0 ? am.getResult() : null;
@@ -1548,7 +1606,14 @@
                 final int N = mActivityMonitors.size();
                 for (int i=0; i<N; i++) {
                     final ActivityMonitor am = mActivityMonitors.get(i);
-                    if (am.match(who, null, intents[0])) {
+                    ActivityResult result = null;
+                    if (am.ignoreMatchingSpecificIntents()) {
+                        result = am.onMatchIntent(intents[0]);
+                    }
+                    if (result != null) {
+                        am.mHits++;
+                        return;
+                    } else if (am.match(who, null, intents[0])) {
                         am.mHits++;
                         if (am.isBlocking()) {
                             return;
@@ -1611,7 +1676,14 @@
                 final int N = mActivityMonitors.size();
                 for (int i=0; i<N; i++) {
                     final ActivityMonitor am = mActivityMonitors.get(i);
-                    if (am.match(who, null, intent)) {
+                    ActivityResult result = null;
+                    if (am.ignoreMatchingSpecificIntents()) {
+                        result = am.onMatchIntent(intent);
+                    }
+                    if (result != null) {
+                        am.mHits++;
+                        return result;
+                    } else if (am.match(who, null, intent)) {
                         am.mHits++;
                         if (am.isBlocking()) {
                             return requestCode >= 0 ? am.getResult() : null;
@@ -1671,7 +1743,14 @@
                 final int N = mActivityMonitors.size();
                 for (int i=0; i<N; i++) {
                     final ActivityMonitor am = mActivityMonitors.get(i);
-                    if (am.match(who, null, intent)) {
+                    ActivityResult result = null;
+                    if (am.ignoreMatchingSpecificIntents()) {
+                        result = am.onMatchIntent(intent);
+                    }
+                    if (result != null) {
+                        am.mHits++;
+                        return result;
+                    } else if (am.match(who, null, intent)) {
                         am.mHits++;
                         if (am.isBlocking()) {
                             return requestCode >= 0 ? am.getResult() : null;
@@ -1710,7 +1789,14 @@
                 final int N = mActivityMonitors.size();
                 for (int i=0; i<N; i++) {
                     final ActivityMonitor am = mActivityMonitors.get(i);
-                    if (am.match(who, null, intent)) {
+                    ActivityResult result = null;
+                    if (am.ignoreMatchingSpecificIntents()) {
+                        result = am.onMatchIntent(intent);
+                    }
+                    if (result != null) {
+                        am.mHits++;
+                        return result;
+                    } else if (am.match(who, null, intent)) {
                         am.mHits++;
                         if (am.isBlocking()) {
                             return requestCode >= 0 ? am.getResult() : null;
@@ -1748,7 +1834,14 @@
                 final int N = mActivityMonitors.size();
                 for (int i=0; i<N; i++) {
                     final ActivityMonitor am = mActivityMonitors.get(i);
-                    if (am.match(who, null, intent)) {
+                    ActivityResult result = null;
+                    if (am.ignoreMatchingSpecificIntents()) {
+                        result = am.onMatchIntent(intent);
+                    }
+                    if (result != null) {
+                        am.mHits++;
+                        return;
+                    } else if (am.match(who, null, intent)) {
                         am.mHits++;
                         if (am.isBlocking()) {
                             return;
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 036b47c..c0bf0c4 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -24,25 +24,25 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.RemoteException;
 import android.os.IBinder;
-import android.os.IUserManager;
+import android.os.Looper;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.UserHandle;
 import android.util.Log;
-import android.view.IWindowManager;
 import android.view.IOnKeyguardExitResult;
-import android.view.WindowManager;
+import android.view.IWindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 
+import java.util.List;
+
 /**
  * Class that can be used to lock and unlock the keyboard. Get an instance of this
  * class by calling {@link android.content.Context#getSystemService(java.lang.String)}
@@ -100,12 +100,9 @@
         Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
         intent.putExtra(EXTRA_TITLE, title);
         intent.putExtra(EXTRA_DESCRIPTION, description);
-        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-            intent.setPackage("com.google.android.apps.wearable.settings");
-        } else {
-            // For security reasons, only allow this to come from system settings.
-            intent.setPackage("com.android.settings");
-        }
+
+        // explicitly set the package for security
+        intent.setPackage(getSettingsPackageForIntent(intent));
         return intent;
     }
 
@@ -126,15 +123,23 @@
         intent.putExtra(EXTRA_TITLE, title);
         intent.putExtra(EXTRA_DESCRIPTION, description);
         intent.putExtra(Intent.EXTRA_USER_ID, userId);
-        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-            intent.setPackage("com.google.android.apps.wearable.settings");
-        } else {
-            // For security reasons, only allow this to come from system settings.
-            intent.setPackage("com.android.settings");
-        }
+
+        // explicitly set the package for security
+        intent.setPackage(getSettingsPackageForIntent(intent));
+
         return intent;
     }
 
+    private String getSettingsPackageForIntent(Intent intent) {
+        List<ResolveInfo> resolveInfos = mContext.getPackageManager()
+                .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
+        for (int i = 0; i < resolveInfos.size(); i++) {
+            return resolveInfos.get(i).activityInfo.packageName;
+        }
+
+        return "com.android.settings";
+    }
+
     /**
      * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
      * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
@@ -322,7 +327,7 @@
      * password.
      */
     public boolean isDeviceLocked() {
-        return isDeviceLocked(UserHandle.getCallingUserId());
+        return isDeviceLocked(UserHandle.myUserId());
     }
 
     /**
@@ -347,7 +352,7 @@
      * @return true if a PIN, pattern or password was set.
      */
     public boolean isDeviceSecure() {
-        return isDeviceSecure(UserHandle.getCallingUserId());
+        return isDeviceSecure(UserHandle.myUserId());
     }
 
     /**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index db1162a..4ab0743 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -262,7 +264,15 @@
         return ai.sharedLibraryFiles;
     }
 
-    public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) {
+    /**
+     * Update the ApplicationInfo for an app. If oldPaths is null, all the paths are considered
+     * new.
+     * @param aInfo The new ApplicationInfo to use for this LoadedApk
+     * @param oldPaths The code paths for the old ApplicationInfo object. null means no paths can
+     *                 be reused.
+     */
+    public void updateApplicationInfo(@NonNull ApplicationInfo aInfo,
+            @Nullable List<String> oldPaths) {
         setApplicationInfo(aInfo);
 
         final List<String> newPaths = new ArrayList<>();
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 09e95df..d2d7b6d 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -174,7 +174,7 @@
     @Override
     public void setContentDescription(CharSequence contentDescription) {
         super.setContentDescription(contentDescription);
-        setTooltip(contentDescription);
+        setTooltipText(contentDescription);
     }
 
     @Override
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index da57873..601dfce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -988,6 +988,32 @@
      */
     public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
 
+    /**
+     * {@link #extras} key: the audio contents of this notification.
+     *
+     * This is for use when rendering the notification on an audio-focused interface;
+     * the audio contents are a complete sound sample that contains the contents/body of the
+     * notification. This may be used in substitute of a Text-to-Speech reading of the
+     * notification. For example if the notification represents a voice message this should point
+     * to the audio of that message.
+     *
+     * The data stored under this key should be a String representation of a Uri that contains the
+     * audio contents in one of the following formats: WAV, PCM 16-bit, AMR-WB.
+     *
+     * This extra is unnecessary if you are using {@code MessagingStyle} since each {@code Message}
+     * has a field for holding data URI. That field can be used for audio.
+     * See {@code Message#setData}.
+     *
+     * Example usage:
+     * <pre>
+     * {@code
+     * Notification.Builder myBuilder = (build your Notification as normal);
+     * myBuilder.getExtras().putString(EXTRA_AUDIO_CONTENTS_URI, myAudioUri.toString());
+     * }
+     * </pre>
+     */
+    public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+
     /** @hide */
     @SystemApi
     public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
@@ -1007,6 +1033,21 @@
      * to attach actions.
      */
     public static class Action implements Parcelable {
+        /**
+         * {@link #extras} key: Keys to a {@link Parcelable} {@link ArrayList} of
+         * {@link RemoteInput}s.
+         *
+         * This is intended for {@link RemoteInput}s that only accept data, meaning
+         * {@link RemoteInput#getAllowFreeFormInput} is false, {@link RemoteInput#getChoices}
+         * is null or empty, and {@link RemoteInput#getAllowedDataTypes is non-null and not
+         * empty. These {@link RemoteInput}s will be ignored by devices that do not
+         * support non-text-based {@link RemoteInput}s. See {@link Builder#build}.
+         *
+         * You can test if a RemoteInput matches these constraints using
+         * {@link RemoteInput#isDataOnly}.
+         */
+        private static final String EXTRA_DATA_ONLY_INPUTS = "android.extra.DATA_ONLY_INPUTS";
+
         private final Bundle mExtras;
         private Icon mIcon;
         private final RemoteInput[] mRemoteInputs;
@@ -1097,13 +1138,28 @@
 
         /**
          * Get the list of inputs to be collected from the user when this action is sent.
-         * May return null if no remote inputs were added.
+         * May return null if no remote inputs were added. Only returns inputs which accept
+         * a text input. For inputs which only accept data use {@link #getDataOnlyRemoteInputs}.
          */
         public RemoteInput[] getRemoteInputs() {
             return mRemoteInputs;
         }
 
         /**
+         * Get the list of inputs to be collected from the user that ONLY accept data when this
+         * action is sent. These remote inputs are guaranteed to return true on a call to
+         * {@link RemoteInput#isDataOnly}.
+         *
+         * May return null if no data-only remote inputs were added.
+         *
+         * This method exists so that legacy RemoteInput collectors that pre-date the addition
+         * of non-textual RemoteInputs do not access these remote inputs.
+         */
+        public RemoteInput[] getDataOnlyRemoteInputs() {
+            return (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS);
+        }
+
+        /**
          * Builder class for {@link Action} objects.
          */
         public static final class Builder {
@@ -1226,9 +1282,32 @@
              * @return the built action
              */
             public Action build() {
-                RemoteInput[] remoteInputs = mRemoteInputs != null
-                        ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
-                return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs,
+                ArrayList<RemoteInput> dataOnlyInputs = new ArrayList<>();
+                RemoteInput[] previousDataInputs =
+                    (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS);
+                if (previousDataInputs != null) {
+                    for (RemoteInput input : previousDataInputs) {
+                        dataOnlyInputs.add(input);
+                    }
+                }
+                List<RemoteInput> textInputs = new ArrayList<>();
+                if (mRemoteInputs != null) {
+                    for (RemoteInput input : mRemoteInputs) {
+                        if (input.isDataOnly()) {
+                            dataOnlyInputs.add(input);
+                        } else {
+                            textInputs.add(input);
+                        }
+                    }
+                }
+                if (!dataOnlyInputs.isEmpty()) {
+                    RemoteInput[] dataInputsArr =
+                            dataOnlyInputs.toArray(new RemoteInput[dataOnlyInputs.size()]);
+                    mExtras.putParcelableArray(EXTRA_DATA_ONLY_INPUTS, dataInputsArr);
+                }
+                RemoteInput[] textInputsArr = textInputs.isEmpty()
+                        ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
+                return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
                         mAllowGeneratedReplies);
             }
         }
@@ -1521,7 +1600,7 @@
             /**
              * Get a hint that this Action should be displayed inline.
              *
-             * @return {@code true} if the Action should be displayed inline, {@code false} 
+             * @return {@code true} if the Action should be displayed inline, {@code false}
              *         otherwise. The default value is {@code false} if this was never set.
              */
             public boolean getHintDisplayActionInline() {
@@ -6975,6 +7054,163 @@
     }
 
     /**
+     * <p>Helper class to add Android TV extensions to notifications. To create a notification
+     * with a TV extension:
+     *
+     * <ol>
+     *  <li>Create an {@link Notification.Builder}, setting any desired properties.
+     *  <li>Create a {@link TvExtender}.
+     *  <li>Set TV-specific properties using the {@code set} methods of
+     *  {@link TvExtender}.
+     *  <li>Call {@link Notification.Builder#extend(Notification.Extender)}
+     *  to apply the extension to a notification.
+     * </ol>
+     *
+     * <pre class="prettyprint">
+     * Notification notification = new Notification.Builder(context)
+     *         ...
+     *         .extend(new TvExtender()
+     *                 .set*(...))
+     *         .build();
+     * </pre>
+     *
+     * <p>TV extensions can be accessed on an existing notification by using the
+     * {@code TvExtender(Notification)} constructor, and then using the {@code get} methods
+     * to access values.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class TvExtender implements Extender {
+        private static final String TAG = "TvExtender";
+
+        private static final String EXTRA_TV_EXTENDER = "android.tv.EXTENSIONS";
+        private static final String EXTRA_FLAGS = "flags";
+        private static final String EXTRA_CONTENT_INTENT = "content_intent";
+        private static final String EXTRA_DELETE_INTENT = "delete_intent";
+        private static final String EXTRA_CHANNEL_ID = "channel_id";
+
+        // Flags bitwise-ored to mFlags
+        private static final int FLAG_AVAILABLE_ON_TV = 0x1;
+
+        private int mFlags;
+        private String mChannelId;
+        private PendingIntent mContentIntent;
+        private PendingIntent mDeleteIntent;
+
+        /**
+         * Create a {@link TvExtender} with default options.
+         */
+        public TvExtender() {
+            mFlags = FLAG_AVAILABLE_ON_TV;
+        }
+
+        /**
+         * Create a {@link TvExtender} from the TvExtender options of an existing Notification.
+         *
+         * @param notif The notification from which to copy options.
+         */
+        public TvExtender(Notification notif) {
+            Bundle bundle = notif.extras == null ?
+                null : notif.extras.getBundle(EXTRA_TV_EXTENDER);
+            if (bundle != null) {
+                mFlags = bundle.getInt(EXTRA_FLAGS);
+                mChannelId = bundle.getString(EXTRA_CHANNEL_ID);
+                mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
+                mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
+            }
+        }
+
+        /**
+         * Apply a TV extension to a notification that is being built. This is typically called by
+         * the {@link Notification.Builder#extend(Notification.Extender)}
+         * method of {@link Notification.Builder}.
+         */
+        @Override
+        public Notification.Builder extend(Notification.Builder builder) {
+            Bundle bundle = new Bundle();
+
+            bundle.putInt(EXTRA_FLAGS, mFlags);
+            bundle.putString(EXTRA_CHANNEL_ID, mChannelId);
+            if (mContentIntent != null) {
+                bundle.putParcelable(EXTRA_CONTENT_INTENT, mContentIntent);
+            }
+
+            if (mDeleteIntent != null) {
+                bundle.putParcelable(EXTRA_DELETE_INTENT, mDeleteIntent);
+            }
+
+            builder.getExtras().putBundle(EXTRA_TV_EXTENDER, bundle);
+            return builder;
+        }
+
+        /**
+         * Returns true if this notification should be shown on TV. This method return true
+         * if the notification was extended with a TvExtender.
+         */
+        public boolean isAvailableOnTv() {
+            return (mFlags & FLAG_AVAILABLE_ON_TV) != 0;
+        }
+
+        /**
+         * Specifies the channel the notification should be delivered on when shown on TV.
+         * It can be different from the channel that the notification is delivered to when
+         * posting on a non-TV device.
+         */
+        public TvExtender setChannel(String channelId) {
+            mChannelId = channelId;
+            return this;
+        }
+
+        /**
+         * Returns the id of the channel this notification posts to on TV.
+         */
+        public String getChannel() {
+            return mChannelId;
+        }
+
+        /**
+         * Supplies a {@link PendingIntent} to be sent when the notification is selected on TV.
+         * If provided, it is used instead of the content intent specified
+         * at the level of Notification.
+         */
+        public TvExtender setContentIntent(PendingIntent intent) {
+            mContentIntent = intent;
+            return this;
+        }
+
+        /**
+         * Returns the TV-specific content intent.  If this method returns null, the
+         * main content intent on the notification should be used.
+         *
+         * @see {@link Notification#contentIntent}
+         */
+        public PendingIntent getContentIntent() {
+            return mContentIntent;
+        }
+
+        /**
+         * Supplies a {@link PendingIntent} to send when the notification is cleared explicitly
+         * by the user on TV.  If provided, it is used instead of the delete intent specified
+         * at the level of Notification.
+         */
+        public TvExtender setDeleteIntent(PendingIntent intent) {
+            mDeleteIntent = intent;
+            return this;
+        }
+
+        /**
+         * Returns the TV-specific delete intent.  If this method returns null, the
+         * main delete intent on the notification should be used.
+         *
+         * @see {@link Notification#deleteIntent}
+         */
+        public PendingIntent getDeleteIntent() {
+            return mDeleteIntent;
+        }
+    }
+
+    /**
      * Get an array of Notification objects from a parcelable array bundle field.
      * Update the bundle to have a typed array so fetches in the future don't need
      * to do an array copy.
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index bdccb8a..56ef791 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -44,6 +44,7 @@
     private static final String TAG_CHANNEL = "channel";
     private static final String ATT_NAME = "name";
     private static final String ATT_ID = "id";
+    private static final String ATT_DELETED = "deleted";
     private static final String ATT_PRIORITY = "priority";
     private static final String ATT_VISIBILITY = "visibility";
     private static final String ATT_IMPORTANCE = "importance";
@@ -120,7 +121,7 @@
             NotificationManager.VISIBILITY_NO_OVERRIDE;
     private static final int DEFAULT_IMPORTANCE =
             NotificationManager.IMPORTANCE_UNSPECIFIED;
-    private static final boolean DEFAULT_ALLOWED = true;
+    private static final boolean DEFAULT_DELETED = false;
 
     private final String mId;
     private CharSequence mName;
@@ -133,7 +134,7 @@
     private int mUserLockedFields;
     private boolean mVibrationEnabled;
     private boolean mShowBadge;
-    private boolean mAllowed = DEFAULT_ALLOWED;
+    private boolean mDeleted = DEFAULT_DELETED;
 
     /**
      * Creates a notification channel.
@@ -170,7 +171,7 @@
         mUserLockedFields = in.readInt();
         mVibrationEnabled = in.readByte() != 0;
         mShowBadge = in.readByte() != 0;
-        mAllowed = in.readByte() != 0;
+        mDeleted = in.readByte() != 0;
     }
 
     @Override
@@ -196,7 +197,7 @@
         dest.writeInt(mUserLockedFields);
         dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
         dest.writeByte(mShowBadge ? (byte) 1 : (byte) 0);
-        dest.writeByte(mAllowed ? (byte) 1 : (byte) 0);
+        dest.writeByte(mDeleted ? (byte) 1 : (byte) 0);
     }
 
     /**
@@ -207,6 +208,14 @@
         mUserLockedFields |= field;
     }
 
+    /**
+     * @hide
+     */
+    @SystemApi
+    public void setDeleted(boolean deleted) {
+        mDeleted = deleted;
+    }
+
     // Modifiable by a notification ranker.
 
     /**
@@ -365,10 +374,11 @@
     }
 
     /**
-     * Returns whether notifications are allowed to post to this channel.
+     * @hide
      */
-    public boolean isAllowed() {
-        return mAllowed;
+    @SystemApi
+    public boolean isDeleted() {
+        return mDeleted;
     }
 
     /**
@@ -393,6 +403,7 @@
         enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
         setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
         setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
+        setDeleted(safeBool(parser, ATT_DELETED, false));
         lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
     }
 
@@ -434,6 +445,9 @@
         if (canShowBadge()) {
             out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
         }
+        if (isDeleted()) {
+            out.attribute(null, ATT_DELETED, Boolean.toString(isDeleted()));
+        }
 
         out.endTag(null, TAG_CHANNEL);
     }
@@ -464,6 +478,7 @@
         record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
         record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
         record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
+        record.put(ATT_DELETED, Boolean.toString(isDeleted()));
         return record;
     }
 
@@ -547,7 +562,7 @@
         if (mUserLockedFields != that.mUserLockedFields) return false;
         if (mVibrationEnabled != that.mVibrationEnabled) return false;
         if (mShowBadge != that.mShowBadge) return false;
-        if (mAllowed != that.mAllowed) return false;
+        if (mDeleted != that.mDeleted) return false;
         if (mId != null ? !mId.equals(that.mId) : that.mId != null) return false;
         if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
         if (mSound != null ? !mSound.equals(that.mSound) : that.mSound != null) return false;
@@ -568,7 +583,7 @@
         result = 31 * result + mUserLockedFields;
         result = 31 * result + (mVibrationEnabled ? 1 : 0);
         result = 31 * result + (mShowBadge ? 1 : 0);
-        result = 31 * result + (mAllowed ? 1 : 0);
+        result = 31 * result + (mDeleted ? 1 : 0);
         return result;
     }
 
@@ -586,7 +601,7 @@
                 ", mUserLockedFields=" + mUserLockedFields +
                 ", mVibrationEnabled=" + mVibrationEnabled +
                 ", mShowBadge=" + mShowBadge +
-                ", mAllowed=" + mAllowed +
+                ", mDeleted=" + mDeleted +
                 '}';
     }
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 3551691..c0aae6d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -24,6 +24,7 @@
 import android.app.Notification.Builder;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
@@ -1085,4 +1086,38 @@
             default: return defValue;
         }
     }
+
+    /**
+     * Start a service directly into the "foreground service" state.  Unlike
+     * {@link android.content.Context#startService(Intent)}, this method
+     * can be used from within background operations like broadcast receivers
+     * or scheduled jobs.
+     *
+     * @param service Description of the service to be stopped.  The Intent must be either
+     *      fully explicit (supplying a component name) or specify a specific package
+     *      name it is targeted to.
+     * @param id The identifier for this notification as per
+     *      {@link #notify(int, Notification) NotificationManager.notify(int, Notification)};
+     *      must not be 0.
+     * @param notification The Notification to be displayed.
+     * @return If the service is being started or is already running, the
+     *      {@link ComponentName} of the actual service that was started is
+     *      returned; else if the service does not exist null is returned.
+     */
+    @Nullable
+    public ComponentName startServiceInForeground(Intent service,
+            int id, Notification notification) {
+        return mContext.startServiceInForeground(service, id, notification);
+    }
+
+    /**
+     * @hide like {@link #startServiceInForeground(Intent, int, Notification)}
+     * but for a specific user.
+     */
+    @Nullable
+    public ComponentName startServiceInForegroundAsUser(Intent service,
+            int id, Notification notification, UserHandle user) {
+        return mContext.startServiceInForegroundAsUser(service, id, notification, user);
+    }
+
 }
diff --git a/core/java/android/app/PictureInPictureArgs.aidl b/core/java/android/app/PictureInPictureArgs.aidl
new file mode 100644
index 0000000..49df39a
--- /dev/null
+++ b/core/java/android/app/PictureInPictureArgs.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.app;
+
+parcelable PictureInPictureArgs;
diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java
new file mode 100644
index 0000000..fbdcbf4
--- /dev/null
+++ b/core/java/android/app/PictureInPictureArgs.java
@@ -0,0 +1,175 @@
+/*
+ * 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;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a set of arguments used to initialize the picture-in-picture mode.
+ */
+public final class PictureInPictureArgs implements Parcelable {
+
+    /**
+     * The expected aspect ratio of the picture-in-picture.
+     */
+    @Nullable
+    private Float mAspectRatio;
+
+    /**
+     * The set of actions that are associated with this activity when in picture in picture.
+     */
+    @Nullable
+    private List<RemoteAction> mUserActions;
+
+    PictureInPictureArgs(Parcel in) {
+        if (in.readInt() != 0) {
+            mAspectRatio = in.readFloat();
+        }
+        if (in.readInt() != 0) {
+            mUserActions = new ArrayList<>();
+            in.readParcelableList(mUserActions, RemoteAction.class.getClassLoader());
+        }
+    }
+
+    /**
+     * Creates a new set of picture-in-picture arguments.
+     */
+    public PictureInPictureArgs() {
+        // Empty constructor
+    }
+
+    /**
+     * Creates a new set of picture-in-picture arguments from the given {@param aspectRatio} and
+     * {@param actions}.
+     */
+    public PictureInPictureArgs(float aspectRatio, List<RemoteAction> actions) {
+        mAspectRatio = aspectRatio;
+        if (actions != null) {
+            mUserActions = new ArrayList<>(actions);
+        }
+    }
+
+    /**
+     * Copies the set parameters from the other picture-in-picture args.
+     * @hide
+     */
+    public void copyOnlySet(PictureInPictureArgs otherArgs) {
+        if (otherArgs.hasSetAspectRatio()) {
+            mAspectRatio = otherArgs.mAspectRatio;
+        }
+        if (otherArgs.hasSetActions()) {
+            mUserActions = otherArgs.mUserActions;
+        }
+    }
+
+    /**
+     * Sets the aspect ratio.
+     * @param aspectRatio the new aspect ratio for picture-in-picture.
+     */
+    public void setAspectRatio(float aspectRatio) {
+        mAspectRatio = aspectRatio;
+    }
+
+    /**
+     * @return the aspect ratio. If none is set, return 0.
+     * @hide
+     */
+    public float getAspectRatio() {
+        if (mAspectRatio != null) {
+            return mAspectRatio;
+        }
+        return 0f;
+    }
+
+    /**
+     * @return whether the aspect ratio is set.
+     * @hide
+     */
+    public boolean hasSetAspectRatio() {
+        return mAspectRatio != null;
+    }
+
+    /**
+     * Sets the user actions.
+     * @param actions the new actions to show in the picture-in-picture menu.
+     */
+    public void setActions(List<RemoteAction> actions) {
+        if (mUserActions != null) {
+            mUserActions = null;
+        }
+        if (actions != null) {
+            mUserActions = new ArrayList<>(actions);
+        }
+    }
+
+    /**
+     * @return the set of user actions.
+     * @hide
+     */
+    public List<RemoteAction> getActions() {
+        return mUserActions;
+    }
+
+    /**
+     * @return whether the user actions are set.
+     * @hide
+     */
+    public boolean hasSetActions() {
+        return mUserActions != null;
+    }
+
+    @Override
+    public PictureInPictureArgs clone() {
+        return new PictureInPictureArgs(mAspectRatio, mUserActions);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        if (mAspectRatio != null) {
+            out.writeInt(1);
+            out.writeFloat(mAspectRatio);
+        } else {
+            out.writeInt(0);
+        }
+        if (mUserActions != null) {
+            out.writeInt(1);
+            out.writeParcelableList(mUserActions, 0);
+        } else {
+            out.writeInt(0);
+        }
+    }
+
+    public static final Creator<PictureInPictureArgs> CREATOR =
+            new Creator<PictureInPictureArgs>() {
+                public PictureInPictureArgs createFromParcel(Parcel in) {
+                    return new PictureInPictureArgs(in);
+                }
+                public PictureInPictureArgs[] newArray(int size) {
+                    return new PictureInPictureArgs[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
new file mode 100644
index 0000000..1f015a6
--- /dev/null
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -0,0 +1,201 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Specialization of {@link SecurityException} that contains additional
+ * information about how to involve the end user to recover from the exception.
+ * <p>
+ * This exception is only appropriate where there is a concrete action the user
+ * can take to recover and make forward progress, such as confirming or entering
+ * authentication credentials.
+ * <p class="note">
+ * Note: legacy code that receives this exception may treat it as a general
+ * {@link SecurityException}, and thus there is no guarantee that the messages
+ * contained will be shown to the end user.
+ * </p>
+ */
+public final class RecoverableSecurityException extends SecurityException implements Parcelable {
+    private static final String TAG = "RecoverableSecurityException";
+
+    private final CharSequence mUserMessage;
+    private final CharSequence mUserActionTitle;
+    private final PendingIntent mUserAction;
+
+    /** {@hide} */
+    public RecoverableSecurityException(Parcel in) {
+        this(new SecurityException(in.readString()), in.readCharSequence(), in.readCharSequence(),
+                PendingIntent.CREATOR.createFromParcel(in));
+    }
+
+    /**
+     * Create an instance ready to be thrown.
+     *
+     * @param cause original cause with details designed for engineering
+     *            audiences.
+     * @param userMessage short message describing the issue for end user
+     *            audiences, which may be shown in a notification or dialog.
+     *            This should be less than 64 characters. For example: <em>PIN
+     *            required to access Document.pdf</em>
+     * @param userActionTitle short title describing the primary action. This
+     *            should be less than 24 characters. For example: <em>Enter
+     *            PIN</em>
+     * @param userAction primary action that will initiate the recovery. This
+     *            must launch an activity that is expected to set
+     *            {@link Activity#setResult(int)} before finishing to
+     *            communicate the final status of the recovery. For example,
+     *            apps that observe {@link Activity#RESULT_OK} may choose to
+     *            immediately retry their operation.
+     */
+    public RecoverableSecurityException(Throwable cause, CharSequence userMessage,
+            CharSequence userActionTitle, PendingIntent userAction) {
+        super(cause.getMessage());
+        mUserMessage = Preconditions.checkNotNull(userMessage);
+        mUserActionTitle = Preconditions.checkNotNull(userActionTitle);
+        mUserAction = Preconditions.checkNotNull(userAction);
+    }
+
+    /**
+     * Return short message describing the issue for end user audiences, which
+     * may be shown in a notification or dialog.
+     */
+    public CharSequence getUserMessage() {
+        return mUserMessage;
+    }
+
+    /**
+     * Return short title describing the primary action.
+     */
+    public CharSequence getUserActionTitle() {
+        return mUserActionTitle;
+    }
+
+    /**
+     * Return primary action that will initiate the recovery.
+     */
+    public PendingIntent getUserAction() {
+        return mUserAction;
+    }
+
+    /**
+     * Convenience method that will show a very simple notification populated
+     * with the details from this exception.
+     * <p>
+     * If you want more flexibility over retrying your original operation once
+     * the user action has finished, consider presenting your own UI that uses
+     * {@link Activity#startIntentSenderForResult} to launch the
+     * {@link PendingIntent#getIntentSender()} from {@link #getUserAction()}
+     * when requested. If the result of that activity is
+     * {@link Activity#RESULT_OK}, you should consider retrying.
+     * <p>
+     * This method will only display the most recent exception from any single
+     * remote UID; notifications from older exceptions will always be replaced.
+     */
+    public void showAsNotification(Context context) {
+        final Notification.Builder builder = new Notification.Builder(context)
+                .setSmallIcon(com.android.internal.R.drawable.ic_print_error)
+                .setContentTitle(mUserActionTitle)
+                .setContentText(mUserMessage)
+                .setContentIntent(mUserAction)
+                .setCategory(Notification.CATEGORY_ERROR);
+
+        final NotificationManager nm = context.getSystemService(NotificationManager.class);
+        nm.notify(TAG, mUserAction.getCreatorUid(), builder.build());
+    }
+
+    /**
+     * Convenience method that will show a very simple dialog populated with the
+     * details from this exception.
+     * <p>
+     * If you want more flexibility over retrying your original operation once
+     * the user action has finished, consider presenting your own UI that uses
+     * {@link Activity#startIntentSenderForResult} to launch the
+     * {@link PendingIntent#getIntentSender()} from {@link #getUserAction()}
+     * when requested. If the result of that activity is
+     * {@link Activity#RESULT_OK}, you should consider retrying.
+     * <p>
+     * This method will only display the most recent exception from any single
+     * remote UID; dialogs from older exceptions will always be replaced.
+     */
+    public void showAsDialog(Activity activity) {
+        final LocalDialog dialog = new LocalDialog();
+        final Bundle args = new Bundle();
+        args.putParcelable(TAG, this);
+        dialog.setArguments(args);
+
+        final String tag = TAG + "_" + mUserAction.getCreatorUid();
+        final FragmentManager fm = activity.getFragmentManager();
+        final FragmentTransaction ft = fm.beginTransaction();
+        final Fragment old = fm.findFragmentByTag(tag);
+        if (old != null) {
+            ft.remove(old);
+        }
+        ft.add(dialog, tag);
+        ft.commitAllowingStateLoss();
+    }
+
+    /** {@hide} */
+    public static class LocalDialog extends DialogFragment {
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final RecoverableSecurityException e = getArguments().getParcelable(TAG);
+            return new AlertDialog.Builder(getActivity())
+                    .setMessage(e.mUserMessage)
+                    .setPositiveButton(e.mUserActionTitle, (dialog, which) -> {
+                        try {
+                            e.mUserAction.send();
+                        } catch (PendingIntent.CanceledException ignored) {
+                        }
+                    })
+                    .setNegativeButton(android.R.string.cancel, null)
+                    .create();
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(getMessage());
+        dest.writeCharSequence(mUserMessage);
+        dest.writeCharSequence(mUserActionTitle);
+        mUserAction.writeToParcel(dest, flags);
+    }
+
+    public static final Creator<RecoverableSecurityException> CREATOR =
+            new Creator<RecoverableSecurityException>() {
+        @Override
+        public RecoverableSecurityException createFromParcel(Parcel source) {
+            return new RecoverableSecurityException(source);
+        }
+
+        @Override
+        public RecoverableSecurityException[] newArray(int size) {
+            return new RecoverableSecurityException[size];
+        }
+    };
+}
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index 11420c5..d1dc859 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -19,9 +19,14 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * A {@code RemoteInput} object specifies input to be collected from a user to be passed along with
@@ -61,9 +66,13 @@
     /** Label used to denote the clip data type used for remote input transport */
     public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
 
-    /** Extra added to a clip data intent object to hold the results bundle. */
+    /** Extra added to a clip data intent object to hold the text results bundle. */
     public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
 
+    /** Extra added to a clip data intent object to hold the data results bundle. */
+    private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
+            "android.remoteinput.dataTypeResultsData";
+
     // Flags bitwise-ored to mFlags
     private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
 
@@ -75,14 +84,16 @@
     private final CharSequence[] mChoices;
     private final int mFlags;
     private final Bundle mExtras;
+    private final ArraySet<String> mAllowedDataTypes;
 
     private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
-            int flags, Bundle extras) {
+            int flags, Bundle extras, ArraySet<String> allowedDataTypes) {
         this.mResultKey = resultKey;
         this.mLabel = label;
         this.mChoices = choices;
         this.mFlags = flags;
         this.mExtras = extras;
+        this.mAllowedDataTypes = allowedDataTypes;
     }
 
     /**
@@ -107,6 +118,21 @@
         return mChoices;
     }
 
+    public Set<String> getAllowedDataTypes() {
+        return mAllowedDataTypes;
+    }
+
+    /**
+     * Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput}
+     * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is
+     * non-null and not empty.
+     */
+    public boolean isDataOnly() {
+        return !getAllowFreeFormInput()
+                && (getChoices() == null || getChoices().length == 0)
+                && !getAllowedDataTypes().isEmpty();
+    }
+
     /**
      * Get whether or not users can provide an arbitrary value for
      * input. If you set this to {@code false}, users must select one of the
@@ -133,6 +159,7 @@
         private CharSequence[] mChoices;
         private int mFlags = DEFAULT_FLAGS;
         private Bundle mExtras = new Bundle();
+        private final ArraySet<String> mAllowedDataTypes = new ArraySet<>();
 
         /**
          * Create a builder object for {@link RemoteInput} objects.
@@ -177,14 +204,34 @@
         /**
          * Specifies whether the user can provide arbitrary values.
          *
-         * @param allowFreeFormInput The default is {@code true}.
-         *         If you specify {@code false}, you must provide a non-null
-         *         and non-empty array to {@link #setChoices} or an
+         * @param mimeType A mime type that results are allowed to come in.
+         *         Be aware that text results (see {@link #setAllowFreeFormInput}
+         *         are allowed by default. If you do not want text results you will have to
+         *         pass false to {@code setAllowFreeFormInput}.
+         * @param doAllow Whether the mime type should be allowed or not.
+         * @return this object for method chaining
+         */
+        public Builder setAllowDataType(String mimeType, boolean doAllow) {
+            if (doAllow) {
+                mAllowedDataTypes.add(mimeType);
+            } else {
+                mAllowedDataTypes.remove(mimeType);
+            }
+            return this;
+        }
+
+        /**
+         * Specifies whether the user can provide arbitrary text values.
+         *
+         * @param allowFreeFormTextInput The default is {@code true}.
+         *         If you specify {@code false}, you must either provide a non-null
+         *         and non-empty array to {@link #setChoices}, or enable a data result
+         *         in {@code setAllowDataType}. Otherwise an
          *         {@link IllegalArgumentException} is thrown.
          * @return this object for method chaining
          */
-        public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
-            setFlag(mFlags, allowFreeFormInput);
+        public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) {
+            setFlag(mFlags, allowFreeFormTextInput);
             return this;
         }
 
@@ -224,7 +271,8 @@
          * object.
          */
         public RemoteInput build() {
-            return new RemoteInput(mResultKey, mLabel, mChoices, mFlags, mExtras);
+            return new RemoteInput(
+                    mResultKey, mLabel, mChoices, mFlags, mExtras, mAllowedDataTypes);
         }
     }
 
@@ -234,32 +282,68 @@
         mChoices = in.readCharSequenceArray();
         mFlags = in.readInt();
         mExtras = in.readBundle();
+        mAllowedDataTypes = (ArraySet<String>) in.readArraySet(null);
     }
 
     /**
-     * Get the remote input results bundle from an intent. The returned Bundle will
-     * contain a key/value for every result key populated by remote input collector.
-     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value.
+     * Similar as {@link #getResultsFromIntent} but retrieves data results for a
+     * specific RemoteInput result. To retrieve a value use:
+     * <pre>
+     * {@code
+     * Map<String, Uri> results =
+     *     RemoteInput.getDataResultsFromIntent(intent, REMOTE_INPUT_KEY);
+     * if (results != null) {
+     *   Uri data = results.get(MIME_TYPE_OF_INTEREST);
+     * }
+     * }
+     * </pre>
+     * @param intent The intent object that fired in response to an action or content intent
+     *               which also had one or more remote input requested.
+     * @param remoteInputResultKey The result key for the RemoteInput you want results for.
+     */
+    public static Map<String, Uri> getDataResultsFromIntent(
+            Intent intent, String remoteInputResultKey) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            return null;
+        }
+        Map<String, Uri> results = new HashMap<>();
+        Bundle extras = clipDataIntent.getExtras();
+        for (String key : extras.keySet()) {
+          if (key.startsWith(EXTRA_DATA_TYPE_RESULTS_DATA)) {
+              String mimeType = key.substring(EXTRA_DATA_TYPE_RESULTS_DATA.length());
+              if (mimeType == null || mimeType.isEmpty()) {
+                  continue;
+              }
+              Bundle bundle = clipDataIntent.getBundleExtra(key);
+              String uriStr = bundle.getString(remoteInputResultKey);
+              if (uriStr == null || uriStr.isEmpty()) {
+                  continue;
+              }
+              results.put(mimeType, Uri.parse(uriStr));
+          }
+        }
+        return results.isEmpty() ? null : results;
+    }
+
+    /**
+     * Get the remote input text results bundle from an intent. The returned Bundle will
+     * contain a key/value for every result key populated with text by remote input collector.
+     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value. For non-text
+     * results use {@link #getDataResultsFromIntent}.
      * @param intent The intent object that fired in response to an action or content intent
      *               which also had one or more remote input requested.
      */
     public static Bundle getResultsFromIntent(Intent intent) {
-        ClipData clipData = intent.getClipData();
-        if (clipData == null) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
             return null;
         }
-        ClipDescription clipDescription = clipData.getDescription();
-        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
-            return null;
-        }
-        if (clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
-            return clipData.getItemAt(0).getIntent().getExtras().getParcelable(EXTRA_RESULTS_DATA);
-        }
-        return null;
+        return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA);
     }
 
     /**
-     * Populate an intent object with the results gathered from remote input. This method
+     * Populate an intent object with the text results gathered from remote input. This method
      * should only be called by remote input collection services when sending results to a
      * pending intent.
      * @param remoteInputs The remote inputs for which results are being provided
@@ -267,20 +351,61 @@
      *               field of the intent will be modified to contain the results.
      * @param results A bundle holding the remote input results. This bundle should
      *                be populated with keys matching the result keys specified in
-     *                {@code remoteInputs} with values being the result per key.
+     *                {@code remoteInputs} with values being the CharSequence results per key.
      */
     public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
             Bundle results) {
-        Bundle resultsBundle = new Bundle();
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        Bundle resultsBundle = clipDataIntent.getBundleExtra(EXTRA_RESULTS_DATA);
+        if (resultsBundle == null) {
+            resultsBundle = new Bundle();
+        }
         for (RemoteInput remoteInput : remoteInputs) {
             Object result = results.get(remoteInput.getResultKey());
             if (result instanceof CharSequence) {
                 resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
             }
         }
-        Intent clipIntent = new Intent();
-        clipIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
-        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipIntent));
+        clipDataIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    /**
+     * Same as {@link #addResultsToIntent} but for setting data results.
+     * @param remoteInput The remote input for which results are being provided
+     * @param intent The intent to add remote input results to. The {@link ClipData}
+     *               field of the intent will be modified to contain the results.
+     * @param results A map of mime type to the Uri result for that mime type.
+     */
+    public static void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+            Map<String, Uri> results) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        for (Map.Entry<String, Uri> entry : results.entrySet()) {
+            String mimeType = entry.getKey();
+            Uri uri = entry.getValue();
+            if (mimeType == null) {
+                continue;
+            }
+            Bundle resultsBundle =
+                    clipDataIntent.getBundleExtra(getExtraResultsKeyForData(mimeType));
+            if (resultsBundle == null) {
+                resultsBundle = new Bundle();
+            }
+            resultsBundle.putString(remoteInput.getResultKey(), uri.toString());
+
+            clipDataIntent.putExtra(getExtraResultsKeyForData(mimeType), resultsBundle);
+        }
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    private static String getExtraResultsKeyForData(String mimeType) {
+        return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
     }
 
     @Override
@@ -295,6 +420,7 @@
         out.writeCharSequenceArray(mChoices);
         out.writeInt(mFlags);
         out.writeBundle(mExtras);
+        out.writeArraySet(mAllowedDataTypes);
     }
 
     public static final Creator<RemoteInput> CREATOR = new Creator<RemoteInput>() {
@@ -308,4 +434,19 @@
             return new RemoteInput[size];
         }
     };
+
+    private static Intent getClipDataIntentFromIntent(Intent intent) {
+        ClipData clipData = intent.getClipData();
+        if (clipData == null) {
+            return null;
+        }
+        ClipDescription clipDescription = clipData.getDescription();
+        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
+            return null;
+        }
+        if (!clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
+            return null;
+        }
+        return clipData.getItemAt(0).getIntent();
+    }
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 45831a3..94a8990 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -916,44 +916,85 @@
                 }
             }
 
-            // Bail early if there is no work to do.
-            if (updatedResourceKeys.isEmpty()) {
-                return;
+            redirectResourcesToNewImplLocked(updatedResourceKeys);
+        }
+    }
+
+    // TODO(adamlesinski): Make this accept more than just overlay directories.
+    final void applyNewResourceDirsLocked(@NonNull final String baseCodePath,
+            @NonNull final String[] newResourceDirs) {
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+                    "ResourcesManager#applyNewResourceDirsLocked");
+
+            final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>();
+            final int implCount = mResourceImpls.size();
+            for (int i = 0; i < implCount; i++) {
+                final ResourcesKey key = mResourceImpls.keyAt(i);
+                final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i);
+                final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
+                if (impl != null && key.mResDir != null && key.mResDir.equals(baseCodePath)) {
+                    updatedResourceKeys.put(impl, new ResourcesKey(
+                            key.mResDir,
+                            key.mSplitResDirs,
+                            newResourceDirs,
+                            key.mLibDirs,
+                            key.mDisplayId,
+                            key.mOverrideConfiguration,
+                            key.mCompatInfo));
+                }
             }
 
-            // Update any references to ResourcesImpl that require reloading.
-            final int resourcesCount = mResourceReferences.size();
-            for (int i = 0; i < resourcesCount; i++) {
-                final Resources r = mResourceReferences.get(i).get();
+            invalidatePath("/");
+
+            redirectResourcesToNewImplLocked(updatedResourceKeys);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+        }
+    }
+
+    private void redirectResourcesToNewImplLocked(
+            @NonNull final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys) {
+        // Bail early if there is no work to do.
+        if (updatedResourceKeys.isEmpty()) {
+            return;
+        }
+
+        // Update any references to ResourcesImpl that require reloading.
+        final int resourcesCount = mResourceReferences.size();
+        for (int i = 0; i < resourcesCount; i++) {
+            final WeakReference<Resources> ref = mResourceReferences.get(i);
+            final Resources r = ref != null ? ref.get() : null;
+            if (r != null) {
+                final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
+                if (key != null) {
+                    final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
+                    if (impl == null) {
+                        throw new Resources.NotFoundException("failed to redirect ResourcesImpl");
+                    }
+                    r.setImpl(impl);
+                }
+            }
+        }
+
+        // Update any references to ResourcesImpl that require reloading for each Activity.
+        for (ActivityResources activityResources : mActivityResourceReferences.values()) {
+            final int resCount = activityResources.activityResources.size();
+            for (int i = 0; i < resCount; i++) {
+                final WeakReference<Resources> ref = activityResources.activityResources.get(i);
+                final Resources r = ref != null ? ref.get() : null;
                 if (r != null) {
                     final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
                     if (key != null) {
                         final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
                         if (impl == null) {
-                            throw new Resources.NotFoundException("failed to load " + libAsset);
+                            throw new Resources.NotFoundException(
+                                    "failed to redirect ResourcesImpl");
                         }
                         r.setImpl(impl);
                     }
                 }
             }
-
-            // Update any references to ResourcesImpl that require reloading for each Activity.
-            for (ActivityResources activityResources : mActivityResourceReferences.values()) {
-                final int resCount = activityResources.activityResources.size();
-                for (int i = 0; i < resCount; i++) {
-                    final Resources r = activityResources.activityResources.get(i).get();
-                    if (r != null) {
-                        final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
-                        if (key != null) {
-                            final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
-                            if (impl == null) {
-                                throw new Resources.NotFoundException("failed to load " + libAsset);
-                            }
-                            r.setImpl(impl);
-                        }
-                    }
-                }
-            }
         }
     }
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 9387019..5d8909c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -118,7 +118,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.text.TextClassificationManager;
+import android.text.FontManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -127,12 +127,14 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.app.ISoundTriggerService;
 import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.font.IFontManager;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.policy.PhoneLayoutInflater;
 
@@ -226,10 +228,10 @@
             }});
 
         registerService(Context.TEXT_CLASSIFICATION_SERVICE, TextClassificationManager.class,
-                new StaticServiceFetcher<TextClassificationManager>() {
+                new CachedServiceFetcher<TextClassificationManager>() {
             @Override
-            public TextClassificationManager createService() {
-                return new TextClassificationManager();
+            public TextClassificationManager createService(ContextImpl ctx) {
+                return new TextClassificationManager(ctx);
             }});
 
         registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
@@ -793,6 +795,15 @@
             public IncidentManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                 return new IncidentManager(ctx);
             }});
+
+        registerService(Context.FONT_SERVICE, FontManager.class,
+                new CachedServiceFetcher<FontManager>() {
+                    @Override
+                    public FontManager createService(ContextImpl ctx)
+                            throws ServiceNotFoundException {
+                        IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE);
+                        return new FontManager(IFontManager.Stub.asInterface(b));
+                    }});
     }
 
     /**
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index ad5e69b..35c67d3 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.content.ComponentName;
 import android.os.RemoteException;
 
@@ -34,7 +35,7 @@
     }
 
     @Override
-    public void onPinnedActivityRestartAttempt() throws RemoteException {
+    public void onPinnedActivityRestartAttempt(ComponentName sourceComponent) throws RemoteException {
     }
 
     @Override
@@ -78,4 +79,9 @@
     @Override
     public void onTaskProfileLocked(int taskId, int userId) {
     }
+
+    @Override
+    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
+            throws RemoteException {
+    }
 }
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index a248bce..34a0c30 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -707,17 +707,24 @@
     }
 
     /**
-     * Allows the receiver to be notified when information about a pending system update is
+     * Called when the information about a pending system update is available.
+     *
+     * <p>Allows the receiver to be notified when information about a pending system update is
      * available from the system update service. The same pending system update can trigger multiple
      * calls to this method, so it is necessary to examine the incoming parameters for details about
      * the update.
-     * <p>
-     * This callback is only applicable to device owners.
+     *
+     * <p>This callback is only applicable to device owners and profile owners.
+     *
+     * <p>To get further information about a pending system update (for example, whether or not the
+     * update is a security patch), the device owner or profile owner can call
+     * {@link DevicePolicyManager#getPendingSystemUpdate}.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
      * @param receivedTime The time as given by {@link System#currentTimeMillis()} indicating when
      *        the current pending update was first available. -1 if no pending update is available.
+     * @see DevicePolicyManager#getPendingSystemUpdate
      */
     public void onSystemUpdatePending(Context context, Intent intent, long receivedTime) {
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c95e011..aa56be6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -20,7 +20,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -28,7 +27,6 @@
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.Activity;
-import android.app.admin.PasswordMetrics;
 import android.app.IServiceConnection;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.content.ComponentName;
@@ -1440,6 +1438,7 @@
         }
         return false;
     }
+
     /**
      * Return true if the given administrator component is currently being removed
      * for the user.
@@ -1456,7 +1455,6 @@
         return false;
     }
 
-
     /**
      * Return a list of all currently active device administrators' component
      * names.  If there are no administrators {@code null} may be
@@ -1487,6 +1485,7 @@
      * or uninstalled.
      * @hide
      */
+    @SystemApi
     public boolean packageHasActiveAdmins(String packageName) {
         return packageHasActiveAdmins(packageName, myUserId());
     }
@@ -3736,13 +3735,13 @@
     }
 
     /**
-     * Called by a device owner to set whether auto time is required. If auto time is required the
-     * user cannot set the date and time, but has to use network date and time.
+     * Called by a device or profile owner to set whether auto time is required. If auto time is
+     * required, no user will be able set the date and time and network date and time will be used.
      * <p>
      * Note: if auto time is required the user can still manually set the time zone.
      * <p>
-     * The calling device admin must be a device owner. If it is not, a security exception will be
-     * thrown.
+     * The calling device admin must be a device or profile owner. If it is not, a security
+     * exception will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param required Whether auto time is set required or not.
@@ -5536,7 +5535,7 @@
      *         {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty
      *         {@link Bundle} if no restrictions have been set.
      * @throws SecurityException if {@code admin} is not a device or profile owner.
-     * @see {@link #setApplicationRestrictionsManagingPackage}
+     * @see #setApplicationRestrictionsManagingPackage
      */
     @WorkerThread
     public @NonNull Bundle getApplicationRestrictions(
@@ -6200,12 +6199,18 @@
     }
 
     /**
-     * Callable by the system update service to notify device owners about pending updates.
-     * The caller must hold {@link android.Manifest.permission#NOTIFY_PENDING_SYSTEM_UPDATE}
-     * permission.
+     * Called by the system update service to notify device and profile owners of pending system
+     * updates.
      *
-     * @param updateReceivedTime The time as given by {@link System#currentTimeMillis()} indicating
-     *        when the current pending update was first available. -1 if no update is available.
+     * The caller must hold {@link android.Manifest.permission#NOTIFY_PENDING_SYSTEM_UPDATE}
+     * permission. This method should only be used when it is unknown whether the pending system
+     * update is a security patch. Otherwise, use
+     * {@link #notifyPendingSystemUpdate(long, boolean)}.
+     *
+     * @param updateReceivedTime The time as given by {@link System#currentTimeMillis()}
+     *         indicating when the current pending update was first available. {@code -1} if no
+     *         update is available.
+     * @see #notifyPendingSystemUpdate(long, boolean)
      * @hide
      */
     @SystemApi
@@ -6213,7 +6218,7 @@
         throwIfParentInstance("notifyPendingSystemUpdate");
         if (mService != null) {
             try {
-                mService.notifyPendingSystemUpdate(updateReceivedTime);
+                mService.notifyPendingSystemUpdate(SystemUpdateInfo.of(updateReceivedTime));
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
@@ -6221,6 +6226,52 @@
     }
 
     /**
+     * Called by the system update service to notify device and profile owners of pending system
+     * updates.
+     *
+     * The caller must hold {@link android.Manifest.permission#NOTIFY_PENDING_SYSTEM_UPDATE}
+     * permission. This method should be used instead of {@link #notifyPendingSystemUpdate(long)}
+     * when it is known whether the pending system update is a security patch.
+     *
+     * @param updateReceivedTime The time as given by {@link System#currentTimeMillis()}
+     *         indicating when the current pending update was first available. {@code -1} if no
+     *         update is available.
+     * @param isSecurityPatch {@code true} if this system update is purely a security patch;
+     *         {@code false} if not.
+     * @see #notifyPendingSystemUpdate(long)
+     * @hide
+     */
+    @SystemApi
+    public void notifyPendingSystemUpdate(long updateReceivedTime, boolean isSecurityPatch) {
+        throwIfParentInstance("notifyPendingSystemUpdate");
+        if (mService != null) {
+            try {
+                mService.notifyPendingSystemUpdate(SystemUpdateInfo.of(updateReceivedTime,
+                        isSecurityPatch));
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Called by device or profile owners to get information about a pending system update.
+     *
+     * @param admin Which profile or device owner this request is associated with.
+     * @return Information about a pending system update or {@code null} if no update pending.
+     * @throws SecurityException if {@code admin} is not a device or profile owner.
+     * @see DeviceAdminReceiver#onSystemUpdatePending(Context, Intent, long)
+     */
+    public @Nullable SystemUpdateInfo getPendingSystemUpdate(@NonNull ComponentName admin) {
+        throwIfParentInstance("getPendingSystemUpdate");
+        try {
+            return mService.getPendingSystemUpdate(admin);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called by profile or device owners to set the default response for future runtime permission
      * requests by applications. The policy can allow for normal operation which prompts the user to
      * grant a permission, or can allow automatic granting or denying of runtime permission requests
@@ -6317,7 +6368,7 @@
      * @see #setPermissionGrantState(ComponentName, String, String, int)
      * @see PackageManager#checkPermission(String, String)
      */
-    public int getPermissionGrantState(@NonNull ComponentName admin, String packageName,
+    public int getPermissionGrantState(@Nullable ComponentName admin, String packageName,
             String permission) {
         throwIfParentInstance("getPermissionGrantState");
         try {
@@ -7122,15 +7173,14 @@
     }
 
     /**
-     * @hide
-     * Enable backup service.
-     * <p>This includes all backup and restore mechanisms.
-     * Setting this to {@code false} will make backup service no-op or return empty results.
+     * Allows the device owner to enable or disable the backup service.
      *
-     * <p>There must be only one user on the device, managed by the device owner.
-     * Otherwise a {@link SecurityException} will be thrown.
+     * <p> Backup service manages all backup and restore mechanisms on the device. Setting this to
+     * false will prevent data from being backed up or restored.
      *
-     * <p>Backup service is off by default when device owner is present.
+     * <p> Backup service is off by default when device owner is present.
+     *
+     * @throws SecurityException if {@code admin} is not a device owner.
      */
     public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
         try {
@@ -7141,8 +7191,12 @@
     }
 
     /**
-     * @hide
+     * Return whether the backup service is enabled by the device owner.
+     *
+     * <p> Backup service manages all backup and restore mechanisms on the device.
+     *
      * @return {@code true} if backup service is enabled, {@code false} otherwise.
+     * @see #setBackupServiceEnabled
      */
     public boolean isBackupServiceEnabled(@NonNull ComponentName admin) {
         try {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 66185d5..80ef557 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
 import android.app.admin.NetworkEvent;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
+import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.admin.PasswordMetrics;
 import android.content.ComponentName;
@@ -263,7 +264,8 @@
     boolean setStatusBarDisabled(in ComponentName who, boolean disabled);
     boolean getDoNotAskCredentialsOnBoot();
 
-    void notifyPendingSystemUpdate(in long updateReceivedTime);
+    void notifyPendingSystemUpdate(in SystemUpdateInfo info);
+    SystemUpdateInfo getPendingSystemUpdate(in ComponentName admin);
 
     void setPermissionPolicy(in ComponentName admin, int policy);
     int  getPermissionPolicy(in ComponentName admin);
diff --git a/core/java/android/app/admin/SystemUpdateInfo.aidl b/core/java/android/app/admin/SystemUpdateInfo.aidl
new file mode 100644
index 0000000..6d14904
--- /dev/null
+++ b/core/java/android/app/admin/SystemUpdateInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 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.admin;
+
+parcelable SystemUpdateInfo;
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
new file mode 100644
index 0000000..6bb9f2d
--- /dev/null
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -0,0 +1,189 @@
+/*
+ * 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.admin;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * A class containing information about a pending system update.
+ */
+public final class SystemUpdateInfo implements Parcelable {
+
+    /**
+     * Represents it is unknown whether the system update is a security patch.
+     */
+    public static final int SECURITY_PATCH_STATE_UNKNOWN = 0;
+
+    /**
+     * Represents the system update is not a security patch.
+     */
+    public static final int SECURITY_PATCH_STATE_FALSE = 1;
+
+    /**
+     * Represents the system update is a security patch.
+     */
+    public static final int SECURITY_PATCH_STATE_TRUE = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SECURITY_PATCH_STATE_FALSE, SECURITY_PATCH_STATE_TRUE, SECURITY_PATCH_STATE_UNKNOWN})
+    public @interface SecurityPatchState {}
+
+    private static final String ATTR_RECEIVED_TIME = "received-time";
+    private static final String ATTR_SECURITY_PATCH_STATE = "security-patch-state";
+    // Tag used to store original build fingerprint to detect when the update is applied.
+    private static final String ATTR_ORIGINAL_BUILD = "original-build";
+
+    private final long mReceivedTime;
+    @SecurityPatchState
+    private final int mSecurityPatchState;
+
+    private SystemUpdateInfo(long receivedTime, @SecurityPatchState int securityPatchState) {
+        this.mReceivedTime = receivedTime;
+        this.mSecurityPatchState = securityPatchState;
+    }
+
+    private SystemUpdateInfo(Parcel in) {
+        mReceivedTime = in.readLong();
+        mSecurityPatchState = in.readInt();
+    }
+
+    /** @hide */
+    @Nullable
+    public static SystemUpdateInfo of(long receivedTime) {
+        return receivedTime == -1
+                ? null : new SystemUpdateInfo(receivedTime, SECURITY_PATCH_STATE_UNKNOWN);
+    }
+
+    /** @hide */
+    @Nullable
+    public static SystemUpdateInfo of(long receivedTime, boolean isSecurityPatch) {
+        return receivedTime == -1 ? null : new SystemUpdateInfo(receivedTime,
+                isSecurityPatch ? SECURITY_PATCH_STATE_TRUE : SECURITY_PATCH_STATE_FALSE);
+    }
+
+    /**
+     * Gets time when the update was first available.
+     * @return Time as given by {@link System#currentTimeMillis()}
+     */
+    public long getReceivedTime() {
+        return mReceivedTime;
+    }
+
+    /**
+     * Gets whether the update is a security patch.
+     * @return {@link #SECURITY_PATCH_STATE_FALSE}, {@link #SECURITY_PATCH_STATE_TRUE}, or
+     *         {@link #SECURITY_PATCH_STATE_UNKNOWN}.
+     */
+    @SecurityPatchState
+    public int getSecurityPatchState() {
+        return mSecurityPatchState;
+    }
+
+    public static final Creator<SystemUpdateInfo> CREATOR =
+            new Creator<SystemUpdateInfo>() {
+                @Override
+                public SystemUpdateInfo createFromParcel(Parcel in) {
+                    return new SystemUpdateInfo(in);
+                }
+
+                @Override
+                public SystemUpdateInfo[] newArray(int size) {
+                    return new SystemUpdateInfo[size];
+                }
+            };
+
+    /** @hide */
+    public void writeToXml(XmlSerializer out, String tag) throws IOException {
+        out.startTag(null, tag);
+        out.attribute(null, ATTR_RECEIVED_TIME, String.valueOf(mReceivedTime));
+        out.attribute(null, ATTR_SECURITY_PATCH_STATE, String.valueOf(mSecurityPatchState));
+        out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT);
+        out.endTag(null, tag);
+    }
+
+    /** @hide */
+    @Nullable
+    public static SystemUpdateInfo readFromXml(XmlPullParser parser) {
+        // If an OTA has been applied (build fingerprint has changed), discard stale info.
+        final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD );
+        if (!Build.FINGERPRINT.equals(buildFingerprint)) {
+            return null;
+        }
+        final long receivedTime =
+                Long.parseLong(parser.getAttributeValue(null, ATTR_RECEIVED_TIME));
+        final int securityPatchState =
+                Integer.parseInt(parser.getAttributeValue(null, ATTR_SECURITY_PATCH_STATE));
+        return new SystemUpdateInfo(receivedTime, securityPatchState);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(getReceivedTime());
+        dest.writeInt(getSecurityPatchState());
+    }
+
+    @Override
+    public String toString() {
+        return String.format("SystemUpdateInfo (receivedTime = %d, securityPatchState = %s)",
+                mReceivedTime, securityPatchStateToString(mSecurityPatchState));
+    }
+
+    private static String securityPatchStateToString(@SecurityPatchState int state) {
+        switch (state) {
+            case SECURITY_PATCH_STATE_FALSE:
+                return "false";
+            case SECURITY_PATCH_STATE_TRUE:
+                return "true";
+            case SECURITY_PATCH_STATE_UNKNOWN:
+                return "unknown";
+            default:
+                throw new IllegalArgumentException("Unrecognized security patch state: " + state);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SystemUpdateInfo that = (SystemUpdateInfo) o;
+        return mReceivedTime == that.mReceivedTime
+                && mSecurityPatchState == that.mSecurityPatchState;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mReceivedTime, mSecurityPatchState);
+    }
+}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 80bc136..540683d 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -136,6 +136,27 @@
      */
     public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
 
+    /**
+     * If this flag is passed to {@link #requestBackup(String[], BackupObserver, int)},
+     * BackupManager will pass a blank old state to BackupAgents of requested packages.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int FLAG_NON_INCREMENTAL_BACKUP = 1;
+
+    /**
+     * Use with {@link #requestBackup} to force backup of
+     * package meta data. Typically you do not need to explicitly request this be backed up as it is
+     * handled internally by the BackupManager. If you are requesting backups with
+     * FLAG_NON_INCREMENTAL, this package won't automatically be backed up and you have to
+     * explicitly request for its backup.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
+
     private Context mContext;
     private static IBackupManager sService;
 
@@ -484,13 +505,34 @@
      */
     @SystemApi
     public int requestBackup(String[] packages, BackupObserver observer) {
+        return requestBackup(packages, observer, 0);
+    }
+
+    /**
+     * Request an immediate backup, providing an observer to which results of the backup operation
+     * will be published. The Android backup system will decide for each package whether it will
+     * be full app data backup or key/value-pair-based backup.
+     *
+     * <p>If this method returns {@link BackupManager#SUCCESS}, the OS will attempt to backup all
+     * provided packages using the remote transport.
+     *
+     * @param packages List of package names to backup.
+     * @param observer The {@link BackupObserver} to receive callbacks during the backup
+     *                 operation. Could be {@code null}.
+     * @param flags    {@link #FLAG_NON_INCREMENTAL_BACKUP}.
+     * @return {@link BackupManager#SUCCESS} on success; nonzero on error.
+     * @throws IllegalArgumentException on null or empty {@code packages} param.
+     * @hide
+     */
+    @SystemApi
+    public int requestBackup(String[] packages, BackupObserver observer, int flags) {
         checkServiceBinder();
         if (sService != null) {
             try {
                 BackupObserverWrapper observerWrapper = observer == null
                         ? null
                         : new BackupObserverWrapper(mContext, observer);
-                return sService.requestBackup(packages, observerWrapper);
+                return sService.requestBackup(packages, observerWrapper, flags);
             } catch (RemoteException e) {
                 Log.e(TAG, "requestBackup() couldn't connect");
             }
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index a320bbf..fe23c28 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -357,7 +357,9 @@
      * @param observer The {@link BackupObserver} to receive callbacks during the backup
      * operation.
      *
+     * @param flags {@link BackupManager#FLAG_NON_INCREMENTAL_BACKUP}.
+     *
      * @return Zero on success; nonzero on error.
      */
-    int requestBackup(in String[] packages, IBackupObserver observer);
+    int requestBackup(in String[] packages, IBackupObserver observer, int flags);
 }
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index d3d02e5..a10de45 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -25,6 +25,7 @@
  */
 interface ITrustManager {
     void reportUnlockAttempt(boolean successful, int userId);
+    void reportUnlockLockout(int timeoutMs, int userId);
     void reportEnabledTrustAgentsChanged(int userId);
     void registerTrustListener(in ITrustListener trustListener);
     void unregisterTrustListener(in ITrustListener trustListener);
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 0f5cb6f..a64a023 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -81,6 +81,26 @@
     }
 
     /**
+     * Reports that user {@param userId} has entered a temporary device lockout.
+     *
+     * This generally occurs when  the user has unsuccessfully tried to unlock the device too many
+     * times. The user will then be unable to unlock the device until a set amount of time has
+     * elapsed.
+     *
+     * @param timeout The amount of time that needs to elapse, in milliseconds, until the user may
+     *    attempt to unlock the device again.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     */
+    public void reportUnlockLockout(int timeoutMs, int userId) {
+        try {
+            mService.reportUnlockLockout(timeoutMs, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Reports that the list of enabled trust agents changed for user {@param userId}.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index cd14469..6ba52b7 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -36,7 +36,6 @@
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.util.SparseArray;
-import android.util.TypedValue;
 import android.widget.RemoteViews;
 import android.widget.RemoteViews.OnClickHandler;
 
@@ -381,15 +380,7 @@
         // Convert complex to dp -- we are getting the AppWidgetProviderInfo from the
         // AppWidgetService, which doesn't have our context, hence we need to do the
         // conversion here.
-        appWidget.minWidth =
-            TypedValue.complexToDimensionPixelSize(appWidget.minWidth, mDisplayMetrics);
-        appWidget.minHeight =
-            TypedValue.complexToDimensionPixelSize(appWidget.minHeight, mDisplayMetrics);
-        appWidget.minResizeWidth =
-            TypedValue.complexToDimensionPixelSize(appWidget.minResizeWidth, mDisplayMetrics);
-        appWidget.minResizeHeight =
-            TypedValue.complexToDimensionPixelSize(appWidget.minResizeHeight, mDisplayMetrics);
-
+        appWidget.updateDimensions(mDisplayMetrics);
         synchronized (mViews) {
             v = mViews.get(appWidgetId);
         }
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 31e779f..9980e966 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -31,7 +31,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.widget.RemoteViews;
 
 import com.android.internal.appwidget.IAppWidgetService;
@@ -760,7 +759,7 @@
             }
             for (AppWidgetProviderInfo info : providers.getList()) {
                 // Converting complex to dp.
-                convertSizesToPixels(info);
+                info.updateDimensions(mDisplayMetrics);
             }
             return providers.getList();
         } catch (RemoteException e) {
@@ -782,7 +781,7 @@
             AppWidgetProviderInfo info = mService.getAppWidgetInfo(mPackageName, appWidgetId);
             if (info != null) {
                 // Converting complex to dp.
-                convertSizesToPixels(info);
+                info.updateDimensions(mDisplayMetrics);
             }
             return info;
         } catch (RemoteException e) {
@@ -1072,18 +1071,6 @@
         }
     }
 
-    private void convertSizesToPixels(AppWidgetProviderInfo info) {
-        // Converting complex to dp.
-        info.minWidth = TypedValue.complexToDimensionPixelSize(info.minWidth,
-                mDisplayMetrics);
-        info.minHeight = TypedValue.complexToDimensionPixelSize(info.minHeight,
-                mDisplayMetrics);
-        info.minResizeWidth = TypedValue.complexToDimensionPixelSize(info.minResizeWidth,
-                mDisplayMetrics);
-        info.minResizeHeight = TypedValue.complexToDimensionPixelSize(info.minResizeHeight,
-                mDisplayMetrics);
-    }
-
     /**
      * Request to pin an app widget on the current launcher. It's up to the launcher to accept this
      * request (optionally showing a user confirmation). If the request is accepted, the caller will
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index b4d79b4..06fdb32 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -26,6 +26,8 @@
 import android.os.Parcelable;
 import android.content.ComponentName;
 import android.os.UserHandle;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
 
 /**
  * Describes the meta data for an installed AppWidget provider.  The fields in this class
@@ -379,6 +381,17 @@
     }
 
     /**
+     * @hide
+     */
+    public void updateDimensions(DisplayMetrics displayMetrics) {
+        // Converting complex to dp.
+        minWidth = TypedValue.complexToDimensionPixelSize(minWidth, displayMetrics);
+        minHeight = TypedValue.complexToDimensionPixelSize(minHeight, displayMetrics);
+        minResizeWidth = TypedValue.complexToDimensionPixelSize(minResizeWidth, displayMetrics);
+        minResizeHeight = TypedValue.complexToDimensionPixelSize(minResizeHeight, displayMetrics);
+    }
+
+    /**
      * Parcelable.Creator that instantiates AppWidgetProviderInfo objects
      */
     public static final Parcelable.Creator<AppWidgetProviderInfo> CREATOR
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index c7c64c4..544b3b95 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -965,38 +965,6 @@
     }
 
     /**
-     * Accept the incoming connection.
-     */
-    public boolean acceptIncomingConnect(BluetoothDevice device) {
-        if (DBG) log("acceptIncomingConnect");
-        if (mService != null && isEnabled()) {
-            try {
-                return mService.acceptIncomingConnect(device);
-            } catch (RemoteException e) {Log.e(TAG, e.toString());}
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-        return false;
-    }
-
-    /**
-     * Reject the incoming connection.
-     */
-    public boolean rejectIncomingConnect(BluetoothDevice device) {
-        if (DBG) log("rejectIncomingConnect");
-        if (mService != null) {
-            try {
-                return mService.rejectIncomingConnect(device);
-            } catch (RemoteException e) {Log.e(TAG, e.toString());}
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
-        }
-        return false;
-    }
-
-    /**
      * Returns current audio state of Audio Gateway.
      *
      * Note: This is an internal function and shouldn't be exposed
@@ -1017,13 +985,15 @@
     /**
      * Sets whether audio routing is allowed.
      *
+     * @param device    remote device
+     * @param allowed   if routing is allowed to the device
      * Note: This is an internal function and shouldn't be exposed
      */
-    public void setAudioRouteAllowed(boolean allowed) {
+    public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) {
         if (VDBG) log("setAudioRouteAllowed");
         if (mService != null && isEnabled()) {
             try {
-                mService.setAudioRouteAllowed(allowed);
+                mService.setAudioRouteAllowed(device, allowed);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -1033,14 +1003,15 @@
 
     /**
      * Returns whether audio routing is allowed.
-     *
+     * @param device    remote device
+     * @return whether the command succeeded
      * Note: This is an internal function and shouldn't be exposed
      */
-    public boolean getAudioRouteAllowed() {
+    public boolean getAudioRouteAllowed(BluetoothDevice device) {
         if (VDBG) log("getAudioRouteAllowed");
         if (mService != null && isEnabled()) {
             try {
-                return mService.getAudioRouteAllowed();
+                return mService.getAudioRouteAllowed(device);
             } catch (RemoteException e) {Log.e(TAG, e.toString());}
         } else {
             Log.w(TAG, "Proxy not attached to service");
@@ -1054,15 +1025,16 @@
      *
      * It setup SCO channel with remote connected Handsfree AG device.
      *
+     * @param device    remote device
      * @return          <code>true</code> if command has been issued successfully;
      *                   <code>false</code> otherwise;
      *                   upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
      *                   intent;
      */
-    public boolean connectAudio() {
+    public boolean connectAudio(BluetoothDevice device) {
         if (mService != null && isEnabled()) {
             try {
-                return mService.connectAudio();
+                return mService.connectAudio(device);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
@@ -1078,15 +1050,16 @@
      *
      * It tears down the SCO channel from remote AG device.
      *
+     * @param   device  remote device
      * @return          <code>true</code> if command has been issued successfully;
      *                   <code>false</code> otherwise;
      *                   upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
      *                   intent;
      */
-    public boolean disconnectAudio() {
+    public boolean disconnectAudio(BluetoothDevice device) {
         if (mService != null && isEnabled()) {
             try {
-                return mService.disconnectAudio();
+                return mService.disconnectAudio(device);
             } catch (RemoteException e) {
                 Log.e(TAG, e.toString());
             }
diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
index a351bd2..e571b00 100644
--- a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -29,9 +29,6 @@
     boolean connect(in BluetoothDevice device);
     boolean disconnect(in BluetoothDevice device);
 
-    boolean acceptIncomingConnect(in BluetoothDevice device);
-    boolean rejectIncomingConnect(in BluetoothDevice device);
-
     List<BluetoothDevice> getConnectedDevices();
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
     int getConnectionState(in BluetoothDevice device);
@@ -58,10 +55,10 @@
     boolean getLastVoiceTagNumber(in BluetoothDevice device);
 
     int getAudioState(in BluetoothDevice device);
-    boolean connectAudio();
-    boolean disconnectAudio();
-    void setAudioRouteAllowed(boolean allowed);
-    boolean getAudioRouteAllowed();
+    boolean connectAudio(in BluetoothDevice device);
+    boolean disconnectAudio(in BluetoothDevice device);
+    void setAudioRouteAllowed(in BluetoothDevice device, boolean allowed);
+    boolean getAudioRouteAllowed(in BluetoothDevice device);
 
     Bundle getCurrentAgFeatures(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index bc5e986..7096771 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -32,6 +32,8 @@
 import android.text.style.URLSpan;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -762,6 +764,18 @@
     static public ClipData newUri(ContentResolver resolver, CharSequence label,
             Uri uri) {
         Item item = new Item(uri);
+        String[] mimeTypes = getMimeTypes(resolver, uri);
+        return new ClipData(label, mimeTypes, item);
+    }
+
+    /**
+     * Finds all applicable MIME types for a given URI.
+     *
+     * @param resolver ContentResolver used to get information about the URI.
+     * @param uri The URI.
+     * @return Returns an array of MIME types.
+     */
+    private static String[] getMimeTypes(ContentResolver resolver, Uri uri) {
         String[] mimeTypes = null;
         if ("content".equals(uri.getScheme())) {
             String realType = resolver.getType(uri);
@@ -769,7 +783,7 @@
             if (realType != null) {
                 if (mimeTypes == null) {
                     mimeTypes = new String[] { realType };
-                } else {
+                } else if (!ArrayUtils.contains(mimeTypes, realType)) {
                     String[] tmp = new String[mimeTypes.length + 1];
                     tmp[0] = realType;
                     System.arraycopy(mimeTypes, 0, tmp, 1, mimeTypes.length);
@@ -780,7 +794,7 @@
         if (mimeTypes == null) {
             mimeTypes = MIMETYPES_TEXT_URILIST;
         }
-        return new ClipData(label, mimeTypes, item);
+        return mimeTypes;
     }
 
     /**
@@ -811,8 +825,8 @@
      * Add a new Item to the overall ClipData container.
      * <p> This method will <em>not</em> update the list of available MIME types in the
      * {@link ClipDescription}. It should be used only when adding items which do not add new
-     * MIME types to this clip. If this is not the case, {@link #ClipData(CharSequence, String[],
-     * Item)} should be used with a complete list of MIME types.
+     * MIME types to this clip. If this is not the case, use {@link #addItem(Item, ContentResolver)}
+     * or call {@link #ClipData(CharSequence, String[], Item)} with a complete list of MIME types.
      * @param item Item to be added.
      */
     public void addItem(Item item) {
@@ -822,6 +836,32 @@
         mItems.add(item);
     }
 
+    /**
+     * Add a new Item to the overall ClipData container.
+     * <p> Unlike {@link #addItem(Item)}, this method will update the list of available MIME types
+     * in the {@link ClipDescription}.
+     * @param item Item to be added.
+     * @param resolver ContentResolver used to get information about the URI possibly contained in
+     * the item.
+     */
+    public void addItem(Item item, ContentResolver resolver) {
+        addItem(item);
+
+        if (item.getHtmlText() != null) {
+            mClipDescription.addMimeTypes(MIMETYPES_TEXT_HTML);
+        } else if (item.getText() != null) {
+            mClipDescription.addMimeTypes(MIMETYPES_TEXT_PLAIN);
+        }
+
+        if (item.getIntent() != null) {
+            mClipDescription.addMimeTypes(MIMETYPES_TEXT_INTENT);
+        }
+
+        if (item.getUri() != null) {
+            mClipDescription.addMimeTypes(getMimeTypes(resolver, item.getUri()));
+        }
+    }
+
     /** @hide */
     public Bitmap getIcon() {
         return mIcon;
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 461d1e0..b33a915a 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -22,6 +22,7 @@
 import android.text.TextUtils;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * Meta-data describing the contents of a {@link ClipData}.  Provides enough
@@ -89,7 +90,7 @@
 
 
     final CharSequence mLabel;
-    final String[] mMimeTypes;
+    private final ArrayList<String> mMimeTypes;
     private PersistableBundle mExtras;
 
     /**
@@ -103,7 +104,7 @@
             throw new NullPointerException("mimeTypes is null");
         }
         mLabel = label;
-        mMimeTypes = mimeTypes;
+        mMimeTypes = new ArrayList<String>(Arrays.asList(mimeTypes));
     }
 
     /**
@@ -111,7 +112,7 @@
      */
     public ClipDescription(ClipDescription o) {
         mLabel = o.mLabel;
-        mMimeTypes = o.mMimeTypes;
+        mMimeTypes = new ArrayList<String>(o.mMimeTypes);
     }
 
     /**
@@ -155,8 +156,9 @@
      * matches the desired MIME type, else false.
      */
     public boolean hasMimeType(String mimeType) {
-        for (int i=0; i<mMimeTypes.length; i++) {
-            if (compareMimeTypes(mMimeTypes[i], mimeType)) {
+        final int size = mMimeTypes.size();
+        for (int i=0; i<size; i++) {
+            if (compareMimeTypes(mMimeTypes.get(i), mimeType)) {
                 return true;
             }
         }
@@ -173,12 +175,13 @@
      */
     public String[] filterMimeTypes(String mimeType) {
         ArrayList<String> array = null;
-        for (int i=0; i<mMimeTypes.length; i++) {
-            if (compareMimeTypes(mMimeTypes[i], mimeType)) {
+        final int size = mMimeTypes.size();
+        for (int i=0; i<size; i++) {
+            if (compareMimeTypes(mMimeTypes.get(i), mimeType)) {
                 if (array == null) {
                     array = new ArrayList<String>();
                 }
-                array.add(mMimeTypes[i]);
+                array.add(mMimeTypes.get(i));
             }
         }
         if (array == null) {
@@ -193,14 +196,26 @@
      * Return the number of MIME types the clip is available in.
      */
     public int getMimeTypeCount() {
-        return mMimeTypes.length;
+        return mMimeTypes.size();
     }
 
     /**
      * Return one of the possible clip MIME types.
      */
     public String getMimeType(int index) {
-        return mMimeTypes[index];
+        return mMimeTypes.get(index);
+    }
+
+    /**
+     * Add MIME types to the clip description.
+     */
+    void addMimeTypes(String[] mimeTypes) {
+        for (int i=0; i!=mimeTypes.length; i++) {
+            final String mimeType = mimeTypes[i];
+            if (!mMimeTypes.contains(mimeType)) {
+                mMimeTypes.add(mimeType);
+            }
+        }
     }
 
     /**
@@ -229,11 +244,12 @@
         if (mMimeTypes == null) {
             throw new NullPointerException("null mime types");
         }
-        if (mMimeTypes.length <= 0) {
+        final int size = mMimeTypes.size();
+        if (size <= 0) {
             throw new IllegalArgumentException("must have at least 1 mime type");
         }
-        for (int i=0; i<mMimeTypes.length; i++) {
-            if (mMimeTypes[i] == null) {
+        for (int i=0; i<size; i++) {
+            if (mMimeTypes.get(i) == null) {
                 throw new NullPointerException("mime type at " + i + " is null");
             }
         }
@@ -275,12 +291,13 @@
     /** @hide */
     public boolean toShortStringTypesOnly(StringBuilder b) {
         boolean first = true;
-        for (int i=0; i<mMimeTypes.length; i++) {
+        final int size = mMimeTypes.size();
+        for (int i=0; i<size; i++) {
             if (!first) {
                 b.append(' ');
             }
             first = false;
-            b.append(mMimeTypes[i]);
+            b.append(mMimeTypes.get(i));
         }
         return !first;
     }
@@ -293,13 +310,13 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         TextUtils.writeToParcel(mLabel, dest, flags);
-        dest.writeStringArray(mMimeTypes);
+        dest.writeStringList(mMimeTypes);
         dest.writePersistableBundle(mExtras);
     }
 
     ClipDescription(Parcel in) {
         mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mMimeTypes = in.createStringArray();
+        mMimeTypes = in.createStringArrayList();
         mExtras = in.readPersistableBundle();
     }
 
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index af5e643..38e6fbe 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -34,8 +34,7 @@
 import android.annotation.UserIdInt;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
-import android.app.LoadedApk;
-import android.app.admin.DevicePolicyManager;
+import android.app.Notification;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -63,6 +62,7 @@
 import android.view.DisplayAdjustments;
 import android.view.ViewDebug;
 import android.view.WindowManager;
+import android.view.textclassifier.TextClassificationManager;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -2508,7 +2508,10 @@
      * {@link ComponentName} of the actual service that was started is
      * returned; else if the service does not exist null is returned.
      *
-     * @throws SecurityException &nbsp;
+     * @throws SecurityException If the caller does not permission to access the service
+     * or the service can not be found.
+     * @throws IllegalStateException If the application is in a state where the service
+     * can not be started (such as not in the foreground in a state when services are allowed).
      *
      * @see #stopService
      * @see #bindService
@@ -2517,6 +2520,17 @@
     public abstract ComponentName startService(Intent service);
 
     /**
+     * Start a service directly into the "foreground service" state.  Unlike {@link #startService},
+     * this method can be used from within background operations like broadcast receivers
+     * or scheduled jobs.  The API entry point for this is in NotificationManager in order to
+     * preserve appropriate public package layering.
+     * @hide
+     */
+    @Nullable
+    public abstract ComponentName startServiceInForeground(Intent service,
+            int id, Notification notification);
+
+    /**
      * Request that a given application service be stopped.  If the service is
      * not running, nothing happens.  Otherwise it is stopped.  Note that calls
      * to startService() are not counted -- this stops the service no matter
@@ -2538,7 +2552,10 @@
      * @return If there is a service matching the given Intent that is already
      * running, then it is stopped and {@code true} is returned; else {@code false} is returned.
      *
-     * @throws SecurityException &nbsp;
+     * @throws SecurityException If the caller does not permission to access the service
+     * or the service can not be found.
+     * @throws IllegalStateException If the application is in a state where the service
+     * can not be started (such as not in the foreground in a state when services are allowed).
      *
      * @see #startService
      */
@@ -2547,9 +2564,18 @@
     /**
      * @hide like {@link #startService(Intent)} but for a specific user.
      */
+    @Nullable
     public abstract ComponentName startServiceAsUser(Intent service, UserHandle user);
 
     /**
+     * @hide like {@link #startServiceInForeground(Intent, int, Notification)}
+     * but for a specific user.
+     */
+    @Nullable
+    public abstract ComponentName startServiceInForegroundAsUser(Intent service,
+            int id, Notification notification, UserHandle user);
+
+    /**
      * @hide like {@link #stopService(Intent)} but for a specific user.
      */
     public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
@@ -2591,7 +2617,8 @@
      *         {@code false} is returned if the connection is not made so you will not
      *         receive the service object.
      *
-     * @throws SecurityException &nbsp;
+     * @throws SecurityException If the caller does not permission to access the service
+     * or the service can not be found.
      *
      * @see #unbindService
      * @see #startService
@@ -3320,10 +3347,10 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.text.TextClassificationManager} for text classification services.
+     * {@link TextClassificationManager} for text classification services.
      *
      * @see #getSystemService
-     * @see android.text.TextClassificationManager
+     * @see TextClassificationManager
      */
     public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
 
@@ -3716,6 +3743,11 @@
     public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
 
     /**
+     * Service that provides System font data.
+     */
+    public static final String FONT_SERVICE = "font";
+
+    /**
      * Service to report a system health "incident"
      * @hide
      */
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 4b6076b..b131ecc 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
+import android.app.Notification;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
@@ -623,6 +624,13 @@
         return mBase.startService(service);
     }
 
+    /** @hide */
+    @Override
+    public ComponentName startServiceInForeground(Intent service,
+            int id, Notification notification) {
+        return mBase.startServiceInForeground(service, id, notification);
+    }
+
     @Override
     public boolean stopService(Intent name) {
         return mBase.stopService(name);
@@ -636,6 +644,13 @@
 
     /** @hide */
     @Override
+    public ComponentName startServiceInForegroundAsUser(Intent service,
+            int id, Notification notification, UserHandle user) {
+        return mBase.startServiceInForegroundAsUser(service, id, notification, user);
+    }
+
+    /** @hide */
+    @Override
     public boolean stopServiceAsUser(Intent name, UserHandle user) {
         return mBase.stopServiceAsUser(name, user);
     }
@@ -653,6 +668,13 @@
         return mBase.bindServiceAsUser(service, conn, flags, user);
     }
 
+    /** @hide */
+    @Override
+    public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+            Handler handler, UserHandle user) {
+        return mBase.bindServiceAsUser(service, conn, flags, handler, user);
+    }
+
     @Override
     public void unbindService(ServiceConnection conn) {
         mBase.unbindService(conn);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d8358f9..c550094 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -715,11 +715,13 @@
     /**
      * Activity Action: Creates a shortcut.
      * <p>Input: Nothing.</p>
-     * <p>Output: An Intent representing the shortcut. The intent must contain three
+     * <p>Output: An Intent representing the {@link android.content.pm.ShortcutInfo} result.</p>
+     * <p>For compatibility with older versions of android the intent may also contain three
      * extras: SHORTCUT_INTENT (value: Intent), SHORTCUT_NAME (value: String),
      * and SHORTCUT_ICON (value: Bitmap) or SHORTCUT_ICON_RESOURCE
      * (value: ShortcutIconResource).</p>
      *
+     * @see android.content.pm.ShortcutManager#createShortcutResultIntent
      * @see #EXTRA_SHORTCUT_INTENT
      * @see #EXTRA_SHORTCUT_NAME
      * @see #EXTRA_SHORTCUT_ICON
@@ -733,26 +735,34 @@
      * The name of the extra used to define the Intent of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     /**
      * The name of the extra used to define the name of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     /**
      * The name of the extra used to define the icon, as a Bitmap, of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
     /**
      * The name of the extra used to define the icon, as a ShortcutIconResource, of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
      * @see android.content.Intent.ShortcutIconResource
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_ICON_RESOURCE =
             "android.intent.extra.shortcut.ICON_RESOURCE";
 
@@ -4832,6 +4842,10 @@
      * or not running) apps, regardless of whether that would be done by default.  By
      * default they will only receive broadcasts if the broadcast has specified an
      * explicit component or package name.
+     *
+     * NOTE: dumpstate uses this flag numerically, so when its value is changed
+     * the broadcast code there must also be changed to match.
+     *
      * @hide
      */
     public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 44dff00..4bd091d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -566,6 +566,7 @@
                     CONFIG_SMALLEST_SCREEN_SIZE,
                     CONFIG_DENSITY,
                     CONFIG_LAYOUT_DIRECTION,
+                    CONFIG_COLORIMETRY,
                     CONFIG_FONT_SCALE,
             })
     @Retention(RetentionPolicy.SOURCE)
@@ -671,6 +672,20 @@
     public static final int CONFIG_LAYOUT_DIRECTION = 0x2000;
     /**
      * Bit in {@link #configChanges} that indicates that the activity
+     * can itself handle the change to the display color gamut or dynamic
+     * range. Set from the {@link android.R.attr#configChanges} attribute.
+     */
+    public static final int CONFIG_COLORIMETRY = 0x4000;
+    /**
+     * Bit in {@link #configChanges} that indicates that the activity
+     * can itself handle asset path changes.  Set from the {@link android.R.attr#configChanges}
+     * attribute. This is not a core resource configuration, but a higher-level value, so its
+     * constant starts at the high bits.
+     * @hide We do not want apps handling this yet, but we do need some kind of bit for diffs.
+     */
+    public static final int CONFIG_ASSETS_PATHS = 0x80000000;
+    /**
+     * Bit in {@link #configChanges} that indicates that the activity
      * can itself handle changes to the font scaling factor.  Set from the
      * {@link android.R.attr#configChanges} attribute.  This is
      * not a core resource configuration, but a higher-level value, so its
@@ -698,6 +713,7 @@
         Configuration.NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,   // SMALLEST SCREEN SIZE
         Configuration.NATIVE_CONFIG_DENSITY,                // DENSITY
         Configuration.NATIVE_CONFIG_LAYOUTDIR,              // LAYOUT DIRECTION
+        Configuration.NATIVE_CONFIG_COLORIMETRY,            // COLORIMETRY
     };
 
     /**
@@ -753,7 +769,8 @@
      * {@link #CONFIG_LOCALE}, {@link #CONFIG_TOUCHSCREEN},
      * {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION},
      * {@link #CONFIG_ORIENTATION}, {@link #CONFIG_SCREEN_LAYOUT},
-     * {@link #CONFIG_DENSITY}, and {@link #CONFIG_LAYOUT_DIRECTION}.
+     * {@link #CONFIG_DENSITY}, {@link #CONFIG_LAYOUT_DIRECTION} and
+     * {@link #CONFIG_COLORIMETRY}.
      * Set from the {@link android.R.attr#configChanges} attribute.
      */
     public int configChanges;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 71071e1..04ab239 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -551,6 +551,13 @@
     public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12;
 
     /**
+     * Value for {@link #privateFlags}: {@code true} means this application
+     * contains a static shared library. Defaults to {@code false} if unspecified.
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_STATIC_SHARED_LIBRARY = 1 << 13;
+
+    /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * {@hide}
      */
@@ -1358,6 +1365,13 @@
     /**
      * @hide
      */
+    public boolean isStaticSharedLibrary() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0;
+    }
+
+    /**
+     * @hide
+     */
     @Override protected ApplicationInfo getApplicationInfo() {
         return this;
     }
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 430c7e7..5152416 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IOnAppsChangedListener;
@@ -60,4 +61,8 @@
             int userId);
 
     boolean hasShortcutHostPermission(String callingPackage);
+
+    ParceledListSlice getShortcutConfigActivities(String packageName, in UserHandle user);
+    IntentSender getShortcutConfigActivityIntent(String callingPackage, in ComponentName component,
+            in UserHandle user);
 }
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 154ff85..ecc8cd6 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -21,6 +21,7 @@
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.PackageInstaller;
 import android.content.pm.ParceledListSlice;
+import android.content.pm.VersionedPackage;
 import android.content.IntentSender;
 
 import android.graphics.Bitmap;
@@ -44,7 +45,7 @@
     void registerCallback(IPackageInstallerCallback callback, int userId);
     void unregisterCallback(IPackageInstallerCallback callback);
 
-    void uninstall(String packageName, String callerPackageName, int flags,
+    void uninstall(in VersionedPackage versionedPackage, String callerPackageName, int flags,
             in IntentSender statusReceiver, int userId);
 
     void setPermissionsResult(int sessionId, boolean accepted);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 19cca8e..ab9af5a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -47,6 +47,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.VersionedPackage;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
@@ -63,6 +64,8 @@
     void checkPackageStartable(String packageName, int userId);
     boolean isPackageAvailable(String packageName, int userId);
     PackageInfo getPackageInfo(String packageName, int flags, int userId);
+    PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage,
+            int flags, int userId);
     int getPackageUid(String packageName, int flags, int userId);
     int[] getPackageGids(String packageName, int flags, int userId);
 
@@ -138,6 +141,8 @@
 
     ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
 
+    ResolveInfo findPersistentPreferredActivity(in Intent intent, int userId);
+
     boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
 
     ParceledListSlice queryIntentActivities(in Intent intent,
@@ -229,18 +234,19 @@
     void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName);
 
     /** @deprecated rawr, don't call AIDL methods directly! */
-    void deletePackageAsUser(in String packageName, IPackageDeleteObserver observer,
-            int userId, int flags);
+    void deletePackageAsUser(in String packageName, int versionCode,
+            IPackageDeleteObserver observer, int userId, int flags);
 
     /**
      * Delete a package for a specific user.
      *
-     * @param packageName The fully qualified name of the package to delete.
+     * @param versionedPackage The package to delete.
      * @param observer a callback to use to notify when the package deletion in finished.
      * @param userId the id of the user for whom to delete the package
      * @param flags - possible values: {@link #DONT_DELETE_DATA}
      */
-    void deletePackage(in String packageName, IPackageDeleteObserver2 observer, int userId, int flags);
+    void deletePackageVersioned(in VersionedPackage versionedPackage,
+            IPackageDeleteObserver2 observer, int userId, int flags);
 
     String getInstallerPackageName(in String packageName);
 
@@ -586,4 +592,6 @@
     List<String> getPreviousCodePaths(in String packageName);
 
     int getInstallReason(String packageName, int userId);
+
+    ParceledListSlice getSharedLibraries(int flags, int userId);
 }
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 91df8e8..c90134a 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -15,6 +15,7 @@
  */
 package android.content.pm;
 
+import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
@@ -45,6 +46,8 @@
     boolean requestPinShortcut(String packageName, in ShortcutInfo shortcut,
             in IntentSender resultIntent, int userId);
 
+    Intent createShortcutResultIntent(String packageName, in ShortcutInfo shortcut, int userId);
+
     void disableShortcuts(String packageName, in List shortcutIds, CharSequence disabledMessage,
             int disabledMessageResId, int userId);
 
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index f12abf3..068973b 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -22,6 +22,7 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -36,6 +37,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Set;
 
 /**
  * The {@link com.android.server.pm.PackageManagerService} maintains some
@@ -43,6 +45,7 @@
  *
  * @hide
  */
+@SystemApi
 public final class IntentFilterVerificationInfo implements Parcelable {
     private static final String TAG = IntentFilterVerificationInfo.class.getName();
 
@@ -55,22 +58,26 @@
     private String mPackageName;
     private int mMainStatus;
 
+    /** @hide */
     public IntentFilterVerificationInfo() {
         mPackageName = null;
         mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
 
+    /** @hide */
     public IntentFilterVerificationInfo(String packageName, ArraySet<String> domains) {
         mPackageName = packageName;
         mDomains = domains;
         mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
 
+    /** @hide */
     public IntentFilterVerificationInfo(XmlPullParser parser)
             throws IOException, XmlPullParserException {
         readFromXml(parser);
     }
 
+    /** @hide */
     public IntentFilterVerificationInfo(Parcel source) {
         readFromParcel(source);
     }
@@ -83,6 +90,7 @@
         return mMainStatus;
     }
 
+    /** @hide */
     public void setStatus(int s) {
         if (s >= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED &&
                 s <= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
@@ -92,14 +100,16 @@
         }
     }
 
-    public ArraySet<String> getDomains() {
+    public Set<String> getDomains() {
         return mDomains;
     }
 
+    /** @hide */
     public void setDomains(ArraySet<String> list) {
         mDomains = list;
     }
 
+    /** @hide */
     public String getDomainsString() {
         StringBuilder sb = new StringBuilder();
         for (String str : mDomains) {
@@ -135,6 +145,7 @@
         }
     }
 
+    /** @hide */
     public void readFromXml(XmlPullParser parser) throws XmlPullParserException,
             IOException {
         mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null);
@@ -170,6 +181,7 @@
         }
     }
 
+    /** @hide */
     public void writeToXml(XmlSerializer serializer) throws IOException {
         serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName);
         serializer.attribute(null, ATTR_STATUS, String.valueOf(mMainStatus));
@@ -180,10 +192,12 @@
         }
     }
 
+    /** @hide */
     public String getStatusString() {
         return getStatusStringFromValue(((long)mMainStatus) << 32);
     }
 
+    /** @hide */
     public static String getStatusStringFromValue(long val) {
         StringBuilder sb = new StringBuilder();
         switch ((int)(val >> 32)) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 4cdd653..c6a8674 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -27,6 +27,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
@@ -60,15 +61,18 @@
 
 /**
  * Class for retrieving a list of launchable activities for the current user and any associated
- * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile.
+ * managed profiles that are visible to the current user, which can be retrieved with
+ * {@link #getProfiles}. This is mainly for use by launchers.
+ *
+ * Apps can be queried for each user profile.
  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
  * for package changes here.
  * <p>
  * To watch for managed profiles being added or removed, register for the following broadcasts:
  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
  * <p>
- * You can retrieve the list of profiles associated with this user with
- * {@link UserManager#getUserProfiles()}.
+ * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
+ * main profile.  Apps can only access profiles returned by {@link #getProfiles()}.
  */
 public class LauncherApps {
 
@@ -375,6 +379,24 @@
     }
 
     /**
+     * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
+     *
+     * <p>If the caller is running on a managed profile, it'll return only the current profile.
+     * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
+     */
+    public List<UserHandle> getProfiles() {
+        final UserManager um = mContext.getSystemService(UserManager.class);
+        if (um.isManagedProfile()) {
+            // If it's a managed profile, only return the current profile.
+            final List result =  new ArrayList(1);
+            result.add(android.os.Process.myUserHandle());
+            return result;
+        } else {
+            return um.getUserProfiles();
+        }
+    }
+
+    /**
      * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
      * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
      *
@@ -384,25 +406,11 @@
      * @return List of launchable activities. Can be an empty list but will not be null.
      */
     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
-        ParceledListSlice<ResolveInfo> activities = null;
         try {
-            activities = mService.getLauncherActivities(packageName, user);
+            return convertToActivityList(mService.getLauncherActivities(packageName, user), user);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
-        if (activities == null) {
-            return Collections.EMPTY_LIST;
-        }
-        ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
-        for (ResolveInfo ri : activities.getList()) {
-            LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
-            if (DEBUG) {
-                Log.v(TAG, "Returning activity for profile " + user + " : "
-                        + lai.getComponentName());
-            }
-            lais.add(lai);
-        }
-        return lais;
     }
 
     /**
@@ -465,6 +473,73 @@
     }
 
     /**
+     * Retrieves a list of config activities for creating {@link ShortcutInfo}.
+     *
+     * @param packageName The specific package to query. If null, it checks all installed packages
+     *            in the profile.
+     * @param user The UserHandle of the profile.
+     * @return List of config activities. Can be an empty list but will not be null.
+     *
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
+     */
+    public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
+            @NonNull UserHandle user) {
+        try {
+            return convertToActivityList(mService.getShortcutConfigActivities(packageName, user),
+                    user);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    private List<LauncherActivityInfo> convertToActivityList(
+            @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
+        if (activities == null) {
+            return Collections.EMPTY_LIST;
+        }
+        ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
+        for (ResolveInfo ri : activities.getList()) {
+            LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
+            if (DEBUG) {
+                Log.v(TAG, "Returning activity for profile " + user + " : "
+                        + lai.getComponentName());
+            }
+            lais.add(lai);
+        }
+        return lais;
+    }
+
+    /**
+     * Returns an intent sender which can be used to start the configure activity for creating
+     * custom shortcuts. Use this method if the provider is in another profile as you are not
+     * allowed to start an activity in another profile.
+     *
+     * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
+     * {@link android.app.Activity#RESULT_OK}.
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
+     *
+     * @throws IllegalStateException when the user is locked or not running.
+     * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
+     *
+     * @see #getPinItemRequest(Intent)
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     * @see android.app.Activity#startIntentSenderForResult
+     */
+    public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
+        try {
+            return mService.getShortcutConfigActivityIntent(
+                    mContext.getPackageName(), info.getComponentName(), info.getUser());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks if the package is installed and enabled for a profile.
      *
      * @param packageName The package to check.
@@ -1131,6 +1206,13 @@
      * Represents a "pin shortcut" request made by an app, which is sent with
      * an {@link #ACTION_CONFIRM_PIN_ITEM} intent to the default launcher app.
      *
+     * <p>Note the launcher may receive a request to pin a shortcut that is already pinned, because
+     * the user may actually want to have multiple icons of the same shortcut on the launcher.
+     * The launcher can tell this case by calling {@link ShortcutInfo#isPinned()} on the shortcut
+     * returned by {@link #getShortcutInfo()}.  In this case, calling {@link #accept()} is optional;
+     * even if the launcher does not call it, the shortcut is already pinned.  Also in this case,
+     * the {@code options} argument to {@link #accept(Bundle)} will be ignored.
+     *
      * @see #EXTRA_PIN_ITEM_REQUEST
      * @see #getPinItemRequest(Intent)
      */
@@ -1195,8 +1277,13 @@
          * {@link #REQUEST_TYPE_APPWIDGET} request.
          */
         @Nullable
-        public AppWidgetProviderInfo getAppWidgetProviderInfo() {
-            return mAppWidgetInfo;
+        public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
+            if (mAppWidgetInfo != null) {
+                AppWidgetProviderInfo info = mAppWidgetInfo.clone();
+                info.updateDimensions(context.getResources().getDisplayMetrics());
+                return info;
+            }
+            return null;
         }
 
         /**
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d40bab5..5d5696b 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -142,7 +142,7 @@
      * {@link PackageManager#GET_INSTRUMENTATION} was set.
      */
     public InstrumentationInfo[] instrumentation;
-    
+
     /**
      * Array of all {@link android.R.styleable#AndroidManifestPermission
      * &lt;permission&gt;} tags included under &lt;manifest&gt;,
@@ -150,7 +150,7 @@
      * {@link PackageManager#GET_PERMISSIONS} was set.
      */
     public PermissionInfo[] permissions;
-    
+
     /**
      * Array of all {@link android.R.styleable#AndroidManifestUsesPermission
      * &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
@@ -160,7 +160,7 @@
      * by the system at install time.
      */
     public String[] requestedPermissions;
-    
+
     /**
      * Array of flags of all {@link android.R.styleable#AndroidManifestUsesPermission
      * &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index db3f637..4de967c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -23,7 +24,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.app.ActivityManager;
-import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.graphics.Bitmap;
@@ -36,9 +36,11 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.annotation.IntRange;
 import android.util.ExceptionUtils;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -256,8 +258,6 @@
      */
     public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
 
-    private final Context mContext;
-    private final PackageManager mPm;
     private final IPackageInstaller mInstaller;
     private final int mUserId;
     private final String mInstallerPackageName;
@@ -265,10 +265,8 @@
     private final ArrayList<SessionCallbackDelegate> mDelegates = new ArrayList<>();
 
     /** {@hide} */
-    public PackageInstaller(Context context, PackageManager pm, IPackageInstaller installer,
+    public PackageInstaller(IPackageInstaller installer,
             String installerPackageName, int userId) {
-        mContext = context;
-        mPm = pm;
         mInstaller = installer;
         mInstallerPackageName = installerPackageName;
         mUserId = userId;
@@ -413,10 +411,35 @@
      * Uninstall the given package, removing it completely from the device. This
      * method is only available to the current "installer of record" for the
      * package.
+     *
+     * @param packageName The package to uninstall.
+     * @param statusReceiver Where to deliver the result.
      */
     public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
+       uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+               statusReceiver);
+    }
+
+    /**
+     * Uninstall the given package with a specific version code, removing it
+     * completely from the device. This method is only available to the current
+     * "installer of record" for the package. If the version code of the package
+     * does not match the one passed in the versioned package argument this
+     * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to
+     * uninstall the latest version of the package.
+     *
+     * @param versionedPackage The versioned package to uninstall.
+     * @param statusReceiver Where to deliver the result.
+     */
+    @RequiresPermission(anyOf = {
+            Manifest.permission.DELETE_PACKAGES,
+            Manifest.permission.REQUEST_DELETE_PACKAGES})
+    public void uninstall(@NonNull VersionedPackage versionedPackage,
+            @NonNull IntentSender statusReceiver) {
+        Preconditions.checkNotNull(versionedPackage, "versionedPackage cannot be null");
         try {
-            mInstaller.uninstall(packageName, mInstallerPackageName, 0, statusReceiver, mUserId);
+            mInstaller.uninstall(versionedPackage, mInstallerPackageName,
+                    0, statusReceiver, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index bc79f41..11830c2 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -24,14 +24,10 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.UserHandle;
-import android.text.BidiFormatter;
 import android.text.Html;
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Printer;
-import android.text.BidiFormatter;
-import android.text.TextPaint;
-import android.text.Html;
 import java.text.Collator;
 import java.util.Comparator;
 
@@ -50,31 +46,31 @@
      * Public name of this item. From the "android:name" attribute.
      */
     public String name;
-    
+
     /**
      * Name of the package that this item is in.
      */
     public String packageName;
-    
+
     /**
      * A string resource identifier (in the package's resources) of this
      * component's label.  From the "label" attribute or, if not set, 0.
      */
     public int labelRes;
-    
+
     /**
      * The string provided in the AndroidManifest file, if any.  You
      * probably don't want to use this.  You probably want
      * {@link PackageManager#getApplicationLabel}
      */
     public CharSequence nonLocalizedLabel;
-    
+
     /**
      * A drawable resource identifier (in the package's resources) of this
      * component's icon.  From the "icon" attribute or, if not set, 0.
      */
     public int icon;
-    
+
     /**
      * A drawable resource identifier (in the package's resources) of this
      * component's banner.  From the "banner" attribute or, if not set, 0.
@@ -85,10 +81,10 @@
      * A drawable resource identifier (in the package's resources) of this
      * component's logo. Logos may be larger/wider than icons and are
      * displayed by certain UI elements in place of a name or name/icon
-     * combination. From the "logo" attribute or, if not set, 0. 
+     * combination. From the "logo" attribute or, if not set, 0.
      */
     public int logo;
-    
+
     /**
      * Additional meta-data associated with this component.  This field
      * will only be filled in if you set the
@@ -124,10 +120,10 @@
      * Retrieve the current textual label associated with this item.  This
      * will call back on the given PackageManager to load the label from
      * the application.
-     * 
+     *
      * @param pm A PackageManager from which the label can be loaded; usually
      * the PackageManager from which you originally retrieved this item.
-     * 
+     *
      * @return Returns a CharSequence containing the item's label.  If the
      * item does not have a label, its name is returned.
      */
@@ -146,7 +142,7 @@
         }
         return packageName;
     }
- 
+
     /**
      * Same as {@link #loadLabel(PackageManager)} with the addition that
      * the returned label is safe for being presented in the UI since it
@@ -207,10 +203,10 @@
      * Retrieve the current graphical icon associated with this item.  This
      * will call back on the given PackageManager to load the icon from
      * the application.
-     * 
+     *
      * @param pm A PackageManager from which the icon can be loaded; usually
      * the PackageManager from which you originally retrieved this item.
-     * 
+     *
      * @return Returns a Drawable containing the item's icon.  If the
      * item does not have an icon, the item's default icon is returned
      * such as the default activity icon.
@@ -259,13 +255,13 @@
 
     /**
      * Retrieve the default graphical icon associated with this item.
-     * 
+     *
      * @param pm A PackageManager from which the icon can be loaded; usually
      * the PackageManager from which you originally retrieved this item.
-     * 
+     *
      * @return Returns a Drawable containing the item's default icon
      * such as the default activity icon.
-     * 
+     *
      * @hide
      */
     public Drawable loadDefaultIcon(PackageManager pm) {
@@ -291,10 +287,10 @@
      * Retrieve the current graphical logo associated with this item. This
      * will call back on the given PackageManager to load the logo from
      * the application.
-     * 
+     *
      * @param pm A PackageManager from which the logo can be loaded; usually
      * the PackageManager from which you originally retrieved this item.
-     * 
+     *
      * @return Returns a Drawable containing the item's logo. If the item
      * does not have a logo, this method will return null.
      */
@@ -307,31 +303,31 @@
         }
         return loadDefaultLogo(pm);
     }
-    
+
     /**
      * Retrieve the default graphical logo associated with this item.
-     * 
+     *
      * @param pm A PackageManager from which the logo can be loaded; usually
      * the PackageManager from which you originally retrieved this item.
-     * 
+     *
      * @return Returns a Drawable containing the item's default logo
      * or null if no default logo is available.
-     * 
+     *
      * @hide
      */
     protected Drawable loadDefaultLogo(PackageManager pm) {
         return null;
     }
-    
+
     /**
      * Load an XML resource attached to the meta-data of this item.  This will
      * retrieved the name meta-data entry, and if defined call back on the
      * given PackageManager to load its XML file from the application.
-     * 
+     *
      * @param pm A PackageManager from which the XML can be loaded; usually
      * the PackageManager from which you originally retrieved this item.
      * @param name Name of the meta-date you would like to load.
-     * 
+     *
      * @return Returns an XmlPullParser you can use to parse the XML file
      * assigned as the given meta-data.  If the meta-data name is not defined
      * or the XML resource could not be found, null is returned.
@@ -373,11 +369,11 @@
                     + " banner=0x" + Integer.toHexString(banner));
         }
     }
-    
+
     protected void dumpBack(Printer pw, String prefix) {
         // no back here
     }
-    
+
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         dest.writeString(name);
         dest.writeString(packageName);
@@ -389,7 +385,7 @@
         dest.writeInt(banner);
         dest.writeInt(showUserIcon);
     }
-    
+
     protected PackageItemInfo(Parcel source) {
         name = source.readString();
         packageName = source.readString();
@@ -406,9 +402,9 @@
     /**
      * Get the ApplicationInfo for the application to which this item belongs,
      * if available, otherwise returns null.
-     * 
+     *
      * @return Returns the ApplicationInfo of this item, or null if not known.
-     * 
+     *
      * @hide
      */
     protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 04e649c..98edbf8 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -20,6 +20,7 @@
 import android.annotation.CheckResult;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -1287,6 +1288,13 @@
     public static final int DELETE_FAILED_ABORTED = -5;
 
     /**
+     * Deletion failed return code: this is passed to the
+     * {@link IPackageDeleteObserver} if the system failed to delete the package
+     * because the packge is a shared library used by other installed packages.
+     * {@hide} */
+    public static final int DELETE_FAILED_USED_SHARED_LIBRARY = -6;
+
+    /**
      * Return code that is passed to the {@link IPackageMoveObserver} when the
      * package has been successfully moved by the system.
      *
@@ -1360,6 +1368,14 @@
     public static final int MOVE_FAILED_DEVICE_ADMIN = -8;
 
     /**
+     * Error code that is passed to the {@link IPackageMoveObserver} if system does not allow
+     * non-system apps to be moved to internal storage.
+     *
+     * @hide
+     */
+    public static final int MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL = -9;
+
+    /**
      * Flag parameter for {@link #movePackage} to indicate that
      * the package should be moved to internal storage if its
      * been installed on external media.
@@ -1428,6 +1444,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED = 0;
 
     /**
@@ -1438,6 +1455,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK = 1;
 
     /**
@@ -1449,6 +1467,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2;
 
     /**
@@ -1460,6 +1479,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3;
 
     /**
@@ -1473,6 +1493,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4;
 
     /**
@@ -1854,6 +1875,20 @@
     public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports telephony carrier restriction mechanism.
+     *
+     * <p>Devices declaring this feature must have an implementation of the
+     * {@link android.telephony.TelephonyManager#getAllowedCarriers} and
+     * {@link android.telephony.TelephonyManager#setAllowedCarriers}.
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_CARRIERLOCK =
+            "android.hardware.telephony.carrierlock";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports connecting to USB devices
      * as the USB host.
@@ -2602,6 +2637,11 @@
     public static final int NOTIFY_PACKAGE_USE_REASONS_COUNT = 8;
 
     /**
+     * Constant for specifying the highest installed package version code.
+     */
+    public static final int VERSION_CODE_HIGHEST = -1;
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      *
@@ -2649,7 +2689,58 @@
             throws NameNotFoundException;
 
     /**
-     * @hide
+     * Retrieve overall information about an application package that is
+     * installed on the system. This method can be used for retrieving
+     * information about packages for which multiple versions can be
+     * installed at the time. Currently only packages hosting static shared
+     * libraries can have multiple installed versions. The method can also
+     * be used to get info for a package that has a single version installed
+     * by passing {@link #VERSION_CODE_HIGHEST} in the {@link VersionedPackage}
+     * constructor.
+     *
+     * @param versionedPackage The versioned packages for which to query.
+     * @param flags Additional option flags. Use any combination of
+     *         {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
+     *         {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
+     *         {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA},
+     *         {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *         {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *         {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES},
+     *         {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES},
+     *         {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS},
+     *         {@link #MATCH_UNINSTALLED_PACKAGES}
+     *         to modify the data returned.
+     *
+     * @return A PackageInfo object containing information about the
+     *         package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the
+     *         package is not found in the list of installed applications, the
+     *         package information is retrieved from the list of uninstalled
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     * @see #GET_ACTIVITIES
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_GIDS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_META_DATA
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
+     * @see #GET_RECEIVERS
+     * @see #GET_SERVICES
+     * @see #GET_SHARED_LIBRARY_FILES
+     * @see #GET_SIGNATURES
+     * @see #GET_URI_PERMISSION_PATTERNS
+     * @see #MATCH_DISABLED_COMPONENTS
+     * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     */
+    public abstract PackageInfo getPackageInfo(VersionedPackage versionedPackage,
+            @PackageInfoFlags int flags) throws NameNotFoundException;
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      *
@@ -2693,6 +2784,8 @@
      * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_UNINSTALLED_PACKAGES
+     *
+     * @hide
      */
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     public abstract PackageInfo getPackageInfoAsUser(String packageName,
@@ -3683,6 +3776,37 @@
     public abstract String[] getSystemSharedLibraryNames();
 
     /**
+     * Get a list of shared libraries on the device.
+     *
+     * @param flags To filter the libraries to return.
+     * @return The shared library list.
+     *
+     * @see #MATCH_FACTORY_ONLY
+     * @see #MATCH_KNOWN_PACKAGES
+     * @see #MATCH_ANY_USER
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     */
+    public abstract @NonNull List<SharedLibraryInfo> getSharedLibraries(
+            @InstallFlags int flags);
+
+    /**
+     * Get a list of shared libraries on the device.
+     *
+     * @param flags To filter the libraries to return.
+     * @param userId The user to query for.
+     * @return The shared library list.
+     *
+     * @see #MATCH_FACTORY_ONLY
+     * @see #MATCH_KNOWN_PACKAGES
+     * @see #MATCH_ANY_USER
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     *
+     * @hide
+     */
+    public abstract @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(
+            @InstallFlags int flags, @UserIdInt int userId);
+
+    /**
      * Get the name of the package hosting the services shared library.
      *
      * @return The library host package.
@@ -4951,6 +5075,7 @@
      *
      * @hide
      */
+    @SystemApi
     public abstract int getIntentVerificationStatusAsUser(String packageName, @UserIdInt int userId);
 
     /**
@@ -4973,6 +5098,7 @@
      *
      * @hide
      */
+    @SystemApi
     public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
             @UserIdInt int userId);
 
@@ -4988,6 +5114,7 @@
      *
      * @hide
      */
+    @SystemApi
     public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
             String packageName);
 
@@ -5002,6 +5129,7 @@
      *
      * @hide
      */
+    @SystemApi
     public abstract List<IntentFilter> getAllIntentFilters(String packageName);
 
     /**
@@ -5015,6 +5143,7 @@
      * @hide
      */
     @TestApi
+    @SystemApi
     public abstract String getDefaultBrowserPackageNameAsUser(@UserIdInt int userId);
 
     /**
@@ -5029,6 +5158,7 @@
      *
      * @hide
      */
+    @SystemApi
     public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName,
             @UserIdInt int userId);
 
@@ -5066,6 +5196,7 @@
      *            indicate that no callback is desired.
      * @hide
      */
+    @RequiresPermission(Manifest.permission.DELETE_PACKAGES)
     public abstract void deletePackage(String packageName, IPackageDeleteObserver observer,
             @DeleteFlags int flags);
 
@@ -5084,11 +5215,11 @@
      * @param userId The user Id
      * @hide
      */
-     @RequiresPermission(anyOf = {
+    @RequiresPermission(anyOf = {
             Manifest.permission.DELETE_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
-    public abstract void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
-            @DeleteFlags int flags, @UserIdInt int userId);
+    public abstract void deletePackageAsUser(@NonNull String packageName,
+            IPackageDeleteObserver observer, @DeleteFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve the package name of the application that installed a package. This identifies
@@ -5829,6 +5960,7 @@
             case DELETE_FAILED_USER_RESTRICTED: return "DELETE_FAILED_USER_RESTRICTED";
             case DELETE_FAILED_OWNER_BLOCKED: return "DELETE_FAILED_OWNER_BLOCKED";
             case DELETE_FAILED_ABORTED: return "DELETE_FAILED_ABORTED";
+            case DELETE_FAILED_USED_SHARED_LIBRARY: return "DELETE_FAILED_USED_SHARED_LIBRARY";
             default: return Integer.toString(status);
         }
     }
@@ -5842,6 +5974,7 @@
             case DELETE_FAILED_USER_RESTRICTED: return PackageInstaller.STATUS_FAILURE_BLOCKED;
             case DELETE_FAILED_OWNER_BLOCKED: return PackageInstaller.STATUS_FAILURE_BLOCKED;
             case DELETE_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;
+            case DELETE_FAILED_USED_SHARED_LIBRARY: return PackageInstaller.STATUS_FAILURE_CONFLICT;
             default: return PackageInstaller.STATUS_FAILURE;
         }
     }
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 2590a6b..a1747c7 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -138,9 +138,8 @@
      * @param userId The user under which to check.
      *
      * @return An {@link ApplicationInfo} containing information about the
-     *         package.
-     * @throws NameNotFoundException if a package with the given name cannot be
-     *             found on the system.
+     *         package, or {@code null} if no application exists with that
+     *         package name.
      */
     public abstract ApplicationInfo getApplicationInfo(String packageName, int userId);
 
@@ -223,6 +222,27 @@
             int userId);
 
     /**
+     * Grants access to the package metadata for an ephemeral application.
+     * <p>
+     * When an ephemeral application explicitly tries to interact with a full
+     * install application [via an activity, service or provider that has been
+     * exposed using the {@code visibleToInstantApp} attribute], the normal
+     * application must be able to see metadata about the connecting ephemeral
+     * app. If the ephemeral application uses an implicit intent [ie action VIEW,
+     * category BROWSABLE], it remains hidden from the launched activity.
+     * <p>
+     * If the {@code sourceUid} is not for an ephemeral app or {@code targetUid}
+     * is not for a fully installed app, this method will be a no-op.
+     *
+     * @param userId the user
+     * @param intent the intent that triggered the grant
+     * @param targetAppId The app ID of the fully installed application
+     * @param ephemeralAppId The app ID of the ephemeral application
+     */
+    public abstract void grantEphemeralAccess(int userId, Intent intent,
+            int targetAppId, int ephemeralAppId);
+
+    /**
      * @return The SetupWizard package name.
      */
     public abstract String getSetupWizardPackageName();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 083e4cc6..d8d7abe 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -179,6 +179,13 @@
     private static final String TAG_PACKAGE = "package";
     private static final String TAG_RESTRICT_UPDATE = "restrict-update";
 
+    /**
+     * Bit mask of all the valid bits that can be set in restartOnConfigChanges.
+     * @hide
+     */
+    private static final int RESTART_ON_CONFIG_CHANGES_MASK =
+            ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
+
     // These are the tags supported by child packages
     private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
     static {
@@ -1366,6 +1373,11 @@
                         "No APK Signature Scheme v2 signature in ephemeral package " + apkPath,
                         e);
                 }
+                // Static shared libraries must use only the V2 signing scheme
+                if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                    throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+                            "Static shared libs must use v2 signature scheme " + apkPath);
+                }
             } catch (Exception e) {
                 // APK Signature Scheme v2 signature was found but did not verify
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
@@ -2561,6 +2573,52 @@
         return fi;
     }
 
+    private boolean parseUsesStaticLibrary(Package pkg, Resources res, XmlResourceParser parser,
+            String[] outError) throws XmlPullParserException, IOException {
+        TypedArray sa = res.obtainAttributes(parser,
+                com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary);
+
+        // Note: don't allow this value to be a reference to a resource that may change.
+        String lname = sa.getNonResourceString(
+                com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);
+        final int version = sa.getInt(
+                com.android.internal.R.styleable.AndroidManifestUsesStaticLibrary_version, -1);
+        String certSha256 = sa.getNonResourceString(com.android.internal.R.styleable
+                .AndroidManifestUsesStaticLibrary_certDigest);
+        sa.recycle();
+
+        // Since an APK providing a static shared lib can only provide the lib - fail if malformed
+        if (lname == null || version < 0 || certSha256 == null) {
+            outError[0] = "Bad uses-static-library declaration name: " + lname + " version: "
+                    + version + " certDigest" + certSha256;
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+            XmlUtils.skipCurrentTag(parser);
+            return false;
+        }
+
+        // Can depend only on one version of the same library
+        if (pkg.usesStaticLibraries != null && pkg.usesStaticLibraries.contains(lname)) {
+            outError[0] = "Depending on multiple versions of static library " + lname;
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+            XmlUtils.skipCurrentTag(parser);
+            return false;
+        }
+
+        lname = lname.intern();
+        // We allow ":" delimiters in the SHA declaration as this is the format
+        // emitted by the certtool making it easy for developers to copy/paste.
+        certSha256 = certSha256.replace(":", "").toLowerCase();
+        pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname);
+        pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+                pkg.usesStaticLibrariesVersions, version);
+        pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String.class,
+                pkg.usesStaticLibrariesCertDigests, certSha256);
+
+        XmlUtils.skipCurrentTag(parser);
+
+        return true;
+    }
+
     private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
             throws XmlPullParserException, IOException {
         TypedArray sa = res.obtainAttributes(parser,
@@ -3409,6 +3467,47 @@
                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                     return false;
                 }
+            } else if (tagName.equals("static-library")) {
+                sa = res.obtainAttributes(parser,
+                        com.android.internal.R.styleable.AndroidManifestStaticLibrary);
+
+                // Note: don't allow this value to be a reference to a resource
+                // that may change.
+                final String lname = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestStaticLibrary_name);
+                final int version = sa.getInt(
+                        com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1);
+
+                sa.recycle();
+
+                // Since the app canot run without a static lib - fail if malformed
+                if (lname == null || version < 0) {
+                    outError[0] = "Bad static-library declaration name: " + lname
+                            + " version: " + version;
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                    XmlUtils.skipCurrentTag(parser);
+                    return false;
+                }
+
+                if (owner.mSharedUserId != null) {
+                    outError[0] = "sharedUserId not allowed in static shared library";
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
+                    XmlUtils.skipCurrentTag(parser);
+                    return false;
+                }
+
+                if (owner.staticSharedLibName != null) {
+                    outError[0] = "Multiple static-shared libs for package " + pkgName;
+                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+                    XmlUtils.skipCurrentTag(parser);
+                    return false;
+                }
+
+                owner.staticSharedLibName = lname.intern();
+                owner.staticSharedLibVersion = version;
+                ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
+
+                XmlUtils.skipCurrentTag(parser);
 
             } else if (tagName.equals("library")) {
                 sa = res.obtainAttributes(parser,
@@ -3424,12 +3523,18 @@
                 if (lname != null) {
                     lname = lname.intern();
                     if (!ArrayUtils.contains(owner.libraryNames, lname)) {
-                        owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);
+                        owner.libraryNames = ArrayUtils.add(
+                                owner.libraryNames, lname);
                     }
                 }
 
                 XmlUtils.skipCurrentTag(parser);
 
+            } else if (tagName.equals("uses-static-library")) {
+                if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
+                    return false;
+                }
+
             } else if (tagName.equals("uses-library")) {
                 sa = res.obtainAttributes(parser,
                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
@@ -3608,6 +3713,11 @@
                     return false;
                 }
 
+            } else if (tagName.equals("uses-static-library")) {
+                if (!parseUsesStaticLibrary(owner, res, parser, outError)) {
+                    return false;
+                }
+
             } else if (tagName.equals("uses-library")) {
                 sa = res.obtainAttributes(parser,
                         com.android.internal.R.styleable.AndroidManifestUsesLibrary);
@@ -3855,7 +3965,9 @@
             a.info.maxRecents = sa.getInt(
                     R.styleable.AndroidManifestActivity_maxRecents,
                     ActivityManager.getDefaultAppRecentsLimitStatic());
-            a.info.configChanges = sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0);
+            a.info.configChanges = getActivityConfigChanges(
+                    sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
+                    sa.getInt(R.styleable.AndroidManifestActivity_restartOnConfigChanges, 0));
             a.info.softInputMode = sa.getInt(
                     R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
 
@@ -3931,10 +4043,10 @@
         }
 
         final boolean hasVisibleToEphemeral =
-                sa.hasValue(R.styleable.AndroidManifestActivity_visibleToEphemeral);
+                sa.hasValue(R.styleable.AndroidManifestActivity_visibleToInstantApps);
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
-                || sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToEphemeral, false);
+                || sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
         if (visibleToEphemeral) {
             a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
         }
@@ -4083,6 +4195,17 @@
         }
     }
 
+    /**
+     * @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml.
+     * @param restartOnConfigChanges The bit mask restartOnConfigChanges fetched from
+     *                               AndroidManifest.xml.
+     * @hide Exposed for unit testing only.
+     */
+    @TestApi
+    public static int getActivityConfigChanges(int configChanges, int restartOnConfigChanges) {
+        return configChanges | ((~restartOnConfigChanges) & RESTART_ON_CONFIG_CHANGES_MASK);
+    }
+
     private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
         TypedArray sw = res.obtainAttributes(attrs,
                 com.android.internal.R.styleable.AndroidManifestLayout);
@@ -4244,7 +4367,7 @@
             }
         }
 
-        // TODO add visibleToInstantApp attribute to activity alias
+        // TODO add visibleToInstantApps attribute to activity alias
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
                 || ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
@@ -4420,10 +4543,10 @@
         }
 
         final boolean hasVisibleToEphemeral =
-                sa.hasValue(R.styleable.AndroidManifestProvider_visibleToEphemeral);
+                sa.hasValue(R.styleable.AndroidManifestProvider_visibleToInstantApps);
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
-                || sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToEphemeral, false);
+                || sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
         if (visibleToEphemeral) {
             p.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
         }
@@ -4731,10 +4854,10 @@
         }
 
         final boolean hasVisibleToEphemeral =
-                sa.hasValue(R.styleable.AndroidManifestService_visibleToEphemeral);
+                sa.hasValue(R.styleable.AndroidManifestService_visibleToInstantApps);
         final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
         final boolean visibleToEphemeral = isEphemeral
-                || sa.getBoolean(R.styleable.AndroidManifestService_visibleToEphemeral, false);
+                || sa.getBoolean(R.styleable.AndroidManifestService_visibleToInstantApps, false);
         if (visibleToEphemeral) {
             s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
         }
@@ -5167,6 +5290,10 @@
 
         public String packageName;
 
+        // The package name declared in the manifest as the package can be
+        // renamed, for example static shared libs use synthetic package names.
+        public String manifestPackageName;
+
         /** Names of any split APKs, ordered by parsed splitName */
         public String[] splitNames;
 
@@ -5221,8 +5348,13 @@
         public Package parentPackage;
         public ArrayList<Package> childPackages;
 
+        public String staticSharedLibName = null;
+        public int staticSharedLibVersion = 0;
         public ArrayList<String> libraryNames = null;
         public ArrayList<String> usesLibraries = null;
+        public ArrayList<String> usesStaticLibraries = null;
+        public int[] usesStaticLibrariesVersions = null;
+        public String[] usesStaticLibrariesCertDigests = null;
         public ArrayList<String> usesOptionalLibraries = null;
         public String[] usesLibraryFiles = null;
 
@@ -5321,6 +5453,7 @@
 
         public Package(String packageName) {
             this.packageName = packageName;
+            this.manifestPackageName = packageName;
             applicationInfo.packageName = packageName;
             applicationInfo.uid = -1;
         }
@@ -5639,6 +5772,7 @@
             final ClassLoader boot = Object.class.getClassLoader();
 
             packageName = dest.readString();
+            manifestPackageName = dest.readString();
             splitNames = dest.readStringArray();
             volumeUuid = dest.readString();
             codePath = dest.readString();
@@ -5679,11 +5813,23 @@
                 childPackages = null;
             }
 
+            staticSharedLibName = dest.readString();
+            staticSharedLibVersion = dest.readInt();
             libraryNames = dest.createStringArrayList();
             usesLibraries = dest.createStringArrayList();
             usesOptionalLibraries = dest.createStringArrayList();
             usesLibraryFiles = dest.readStringArray();
 
+            final int libCount = dest.readInt();
+            if (libCount > 0) {
+                usesStaticLibraries = new ArrayList<>(libCount);
+                dest.readStringList(usesStaticLibraries);
+                usesStaticLibrariesVersions = new int[libCount];
+                dest.readIntArray(usesStaticLibrariesVersions);
+                usesStaticLibrariesCertDigests = new String[libCount];
+                dest.readStringArray(usesStaticLibrariesCertDigests);
+            }
+
             preferredActivityFilters = new ArrayList<>();
             dest.readParcelableList(preferredActivityFilters, boot);
             if (preferredActivityFilters.size() == 0) {
@@ -5769,6 +5915,7 @@
         @Override
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(packageName);
+            dest.writeString(manifestPackageName);
             dest.writeStringArray(splitNames);
             dest.writeString(volumeUuid);
             dest.writeString(codePath);
@@ -5793,11 +5940,22 @@
             dest.writeStringList(protectedBroadcasts);
             dest.writeParcelable(parentPackage, flags);
             dest.writeParcelableList(childPackages, flags);
+            dest.writeString(staticSharedLibName);
+            dest.writeInt(staticSharedLibVersion);
             dest.writeStringList(libraryNames);
             dest.writeStringList(usesLibraries);
             dest.writeStringList(usesOptionalLibraries);
             dest.writeStringArray(usesLibraryFiles);
 
+            if (ArrayUtils.isEmpty(usesStaticLibraries)) {
+                dest.writeInt(-1);
+            } else {
+                dest.writeInt(usesStaticLibraries.size());
+                dest.writeStringList(usesStaticLibraries);
+                dest.writeIntArray(usesStaticLibrariesVersions);
+                dest.writeStringArray(usesStaticLibrariesCertDigests);
+            }
+
             dest.writeParcelableList(preferredActivityFilters, flags);
 
             dest.writeStringList(mOriginalPackages);
@@ -6219,6 +6377,9 @@
                 && p.usesLibraryFiles != null) {
             return true;
         }
+        if (p.staticSharedLibName != null) {
+            return true;
+        }
         return false;
     }
 
diff --git a/core/java/android/content/pm/SharedLibraryInfo.aidl b/core/java/android/content/pm/SharedLibraryInfo.aidl
new file mode 100644
index 0000000..56d7c832
--- /dev/null
+++ b/core/java/android/content/pm/SharedLibraryInfo.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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.content.pm;
+
+parcelable SharedLibraryInfo;
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
new file mode 100644
index 0000000..d79deb2
--- /dev/null
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -0,0 +1,216 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class provides information for a shared library. There are
+ * three types of shared libraries: builtin - non-updatable part of
+ * the OS; dynamic - updatable backwards-compatible dynamically linked;
+ * static - updatable non backwards-compatible emulating static linking.
+ */
+public final class SharedLibraryInfo implements Parcelable {
+    /**
+     * Shared library type: this library is a part of the OS
+     * and cannot be updated or uninstalled.
+     * @hide
+     */
+    public static final int TYPE_BUILTIN = 0x1<<0;
+
+    /**
+     * Shared library type: this library is backwards-compatible, can
+     * be updated, and updates can be uninstalled. Clients link against
+     * the latest version of the library.
+     * @hide
+     */
+    public static final int TYPE_DYNAMIC = 0x1<<1;
+
+    /**
+     * Shared library type: this library is <strong>not</strong> backwards
+     * -compatible, can be updated and updates can be uninstalled. Clients
+     * link against a specific version of the library.
+     * @hide
+     */
+    public static final int TYPE_STATIC = 0x1<<2;
+
+    /**
+     * Constant for referring to an undefined version.
+     */
+    public static final int VERSION_UNDEFINED = -1;
+
+    private final String mName;
+    private final int mVersion;
+    private final int mType;
+    private final VersionedPackage mDeclaringPackage;
+    private final List<VersionedPackage> mDependentPackages;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name The lib name.
+     * @param version The lib version if not builtin.
+     * @param type The lib type.
+     * @param declaringPackage The package that declares the library.
+     * @param dependentPackages The packages that depend on the library.
+     *
+     * @hide
+     */
+    public SharedLibraryInfo(String name, int version, int type,
+            VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) {
+        mName = name;
+        mVersion = version;
+        mType = type;
+        mDeclaringPackage = declaringPackage;
+        mDependentPackages = dependentPackages;
+    }
+
+    private SharedLibraryInfo(Parcel parcel) {
+        this(parcel.readString(), parcel.readInt(), parcel.readInt(),
+                parcel.readParcelable(null), parcel.readArrayList(null));
+    }
+
+    /** @hide */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Gets the library name.
+     *
+     * @return The name.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Gets the version of the library. For {@link #isStatic()}  static} libraries
+     * this is the declared version and for {@link #isDynamic()} dynamic} and
+     * {@link #isBuiltin()} builtin} it is {@link #VERSION_UNDEFINED} as these
+     * are not versioned.
+     *
+     * @return The version.
+     */
+    public @IntRange(from = -1) int getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * @return whether this library is builtin which means that it
+     * is a part of the OS and cannot be updated or uninstalled.
+     */
+    public boolean isBuiltin() {
+        return mType == TYPE_BUILTIN;
+    }
+
+    /**
+     * @return whether this library is dynamic which means that it
+     * is backwards-compatible, can be updated, and updates can be
+     * uninstalled. Clients link against the latest version of the
+     * library.
+     */
+    public boolean isDynamic() {
+        return mType == TYPE_DYNAMIC;
+    }
+
+    /**
+     * @return whether this library is dynamic which means that it
+     * is <strong>not</strong> backwards-compatible, can be updated
+     * and updates can be uninstalled. Clients link against a specific
+     * version of the library.
+     */
+    public boolean isStatic() {
+        return mType == TYPE_STATIC;
+    }
+
+    /**
+     * Gets the package that declares the library.
+     *
+     * @return The package declaring the library.
+     */
+    public @NonNull VersionedPackage getDeclaringPackage() {
+        return mDeclaringPackage;
+    }
+
+    /**
+     * Gets the packages that depend on the library.
+     *
+     * @return The dependent packages.
+     */
+    public @NonNull List<VersionedPackage> getDependentPackages() {
+        if (mDependentPackages == null) {
+            return Collections.emptyList();
+        }
+        return mDependentPackages;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "SharedLibraryInfo[name:" + mName + ", type:" + typeToString(mType)
+                + ", version:" + mVersion + (!getDependentPackages().isEmpty()
+                ? " has dependents" : "");
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mName);
+        parcel.writeInt(mVersion);
+        parcel.writeInt(mType);
+        parcel.writeParcelable(mDeclaringPackage, flags);
+        parcel.writeList(mDependentPackages);
+    }
+
+    private static String typeToString(int type) {
+        switch (type) {
+            case TYPE_BUILTIN: {
+                return "builtin";
+            }
+            case TYPE_DYNAMIC: {
+                return "dynamic";
+            }
+            case TYPE_STATIC: {
+                return "static";
+            }
+            default: {
+                return "unknown";
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<SharedLibraryInfo> CREATOR =
+            new Parcelable.Creator<SharedLibraryInfo>() {
+        public SharedLibraryInfo createFromParcel(Parcel source) {
+            return new SharedLibraryInfo(source);
+        }
+
+        public SharedLibraryInfo[] newArray(int size) {
+            return new SharedLibraryInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 3853400..805054f 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -881,6 +881,31 @@
     }
 
     /**
+     * Returns an Intent which can be used by the default launcher to pin {@param shortcut}.
+     * This should be used by an Activity to set result in response to
+     * {@link Intent#ACTION_CREATE_SHORTCUT}.
+     *
+     * @param shortcut New shortcut to pin.  If an app wants to pin an existing (either dynamic
+     *     or manifest) shortcut, then it only needs to have an ID, and other fields don't have to
+     *     be set, in which case, the target shortcut must be enabled.
+     *     If it's a new shortcut, all the mandatory fields, such as a short label, must be
+     *     set.
+     * @return The intent that should be set as the result for the calling activity or null.
+     *
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     *
+     * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled.
+     */
+    public Intent createShortcutResultIntent(@NonNull ShortcutInfo shortcut) {
+        try {
+            return mService.createShortcutResultIntent(mContext.getPackageName(), shortcut,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called internally when an app is considered to have come to the foreground
      * even when technically it's not.  This method resets the throttling for this package.
      * For example, when the user sends an "inline reply" on a notification, the system UI will
diff --git a/core/java/android/content/pm/VersionedPackage.aidl b/core/java/android/content/pm/VersionedPackage.aidl
new file mode 100644
index 0000000..43412a4
--- /dev/null
+++ b/core/java/android/content/pm/VersionedPackage.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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.content.pm;
+
+parcelable VersionedPackage;
diff --git a/core/java/android/content/pm/VersionedPackage.java b/core/java/android/content/pm/VersionedPackage.java
new file mode 100644
index 0000000..83e7815
--- /dev/null
+++ b/core/java/android/content/pm/VersionedPackage.java
@@ -0,0 +1,100 @@
+/*
+ * 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.content.pm;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Encapsulates a package and its version code.
+ */
+public final class VersionedPackage implements Parcelable {
+    private final String mPackageName;
+    private final long mVersionCode;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntRange(from = PackageManager.VERSION_CODE_HIGHEST)
+    public @interface VersionCode{}
+
+    /**
+     * Creates a new instance. Use {@link PackageManager#VERSION_CODE_HIGHEST}
+     * to refer to the highest version code of this package.
+     * @param packageName The package name.
+     * @param versionCode The version code.
+     */
+    public VersionedPackage(@NonNull String packageName,
+            @VersionCode int versionCode) {
+        mPackageName = packageName;
+        mVersionCode = versionCode;
+    }
+
+    private VersionedPackage(Parcel parcel) {
+        mPackageName = parcel.readString();
+        mVersionCode = parcel.readLong();
+    }
+
+    /**
+     * Gets the package name.
+     *
+     * @return The package name.
+     */
+    public @NonNull String getPackageName() {
+        return mPackageName;
+    }
+
+    /**
+     * Gets the version code.
+     *
+     * @return The version code.
+     */
+    public @VersionCode long getVersionCode() {
+        return mVersionCode;
+    }
+
+    @Override
+    public String toString() {
+        return "VersionedPackage[" + mPackageName + "/" + mVersionCode + "]";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mPackageName);
+        parcel.writeLong(mVersionCode);
+    }
+
+    public static final Creator<VersionedPackage> CREATOR = new Creator<VersionedPackage>() {
+        @Override
+        public VersionedPackage createFromParcel(Parcel source) {
+            return new VersionedPackage(source);
+        }
+
+        @Override
+        public VersionedPackage[] newArray(int size) {
+            return new VersionedPackage[size];
+        }
+    };
+}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 48860f7..a81329d 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -101,6 +101,68 @@
      */
     public boolean userSetLocale;
 
+
+    /** Constant for {@link #colorimetry}: bits that encode whether the screen is wide gamut. */
+    public static final int COLORIMETRY_WIDE_COLOR_GAMUT_MASK = 0x3;
+    /**
+     * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} value
+     * indicating that it is unknown whether or not the screen is wide gamut.
+     */
+    public static final int COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED = 0x0;
+    /**
+     * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} value
+     * indicating that the screen is not wide gamut.
+     * <p>Corresponds to the <code>-nowidecg</code> resource qualifier.</p>
+     */
+    public static final int COLORIMETRY_WIDE_COLOR_GAMUT_NO = 0x1;
+    /**
+     * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} value
+     * indicating that the screen is wide gamut.
+     * <p>Corresponds to the <code>-widecg</code> resource qualifier.</p>
+     */
+    public static final int COLORIMETRY_WIDE_COLOR_GAMUT_YES = 0x2;
+
+    /** Constant for {@link #colorimetry}: bits that encode whether the dynamic range of the screen. */
+    public static final int COLORIMETRY_HDR_MASK = 0xc;
+    /** Constant for {@link #colorimetry}: bits shift to get the screen dynamic range. */
+    public static final int COLORIMETRY_HDR_SHIFT = 2;
+    /**
+     * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_HDR_MASK} value
+     * indicating that it is unknown whether or not the screen is HDR.
+     */
+    public static final int COLORIMETRY_HDR_UNDEFINED = 0x0;
+    /**
+     * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_HDR_MASK} value
+     * indicating that the screen is not HDR (low/standard dynamic range).
+     * <p>Corresponds to the <code>-lowdr</code> resource qualifier.</p>
+     */
+    public static final int COLORIMETRY_HDR_NO = 0x1 << COLORIMETRY_HDR_SHIFT;
+    /**
+     * Constant for {@link #colorimetry}: a {@link #COLORIMETRY_HDR_MASK} value
+     * indicating that the screen is HDR (dynamic range).
+     * <p>Corresponds to the <code>-highdr</code> resource qualifier.</p>
+     */
+    public static final int COLORIMETRY_HDR_YES = 0x2 << COLORIMETRY_HDR_SHIFT;
+
+    /** Constant for {@link #colorimetry}: a value indicating that colorimetry is undefined */
+    @SuppressWarnings("PointlessBitwiseExpression")
+    public static final int COLORIMETRY_UNDEFINED = COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED |
+            COLORIMETRY_HDR_UNDEFINED;
+
+    /**
+     * Bit mask of for color capabilities of the screen. Currently there are two fields:
+     * <p>The {@link #COLORIMETRY_WIDE_COLOR_GAMUT_MASK} bits define the color gamut of
+     * the screen. They may be one of
+     * {@link #COLORIMETRY_WIDE_COLOR_GAMUT_NO} or {@link #COLORIMETRY_WIDE_COLOR_GAMUT_YES}.</p>
+     *
+     * <p>The {@link #COLORIMETRY_HDR_MASK} defines the dynamic range of the screen. They may be
+     * one of {@link #COLORIMETRY_HDR_NO} or {@link #COLORIMETRY_HDR_YES}.</p>
+     *
+     * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+     * Multiple Screens</a> for more information.</p>
+     */
+    public int colorimetry;
+
     /** Constant for {@link #screenLayout}: bits that encode the size. */
     public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
     /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
@@ -331,6 +393,9 @@
         if ((diff & ActivityInfo.CONFIG_SCREEN_LAYOUT) != 0) {
             list.add("CONFIG_SCREEN_LAYOUT");
         }
+        if ((diff & ActivityInfo.CONFIG_COLORIMETRY) != 0) {
+            list.add("CONFIG_COLORIMETRY");
+        }
         if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0) {
             list.add("CONFIG_UI_MODE");
         }
@@ -346,6 +411,9 @@
         if ((diff & ActivityInfo.CONFIG_FONT_SCALE) != 0) {
             list.add("CONFIG_FONT_SCALE");
         }
+        if ((diff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
+            list.add("CONFIG_ASSETS_PATHS");
+        }
         StringBuilder builder = new StringBuilder("{");
         for (int i = 0, n = list.size(); i < n; i++) {
             builder.append(list.get(i));
@@ -671,6 +739,21 @@
     public int compatSmallestScreenWidthDp;
 
     /**
+     * An undefined assetsSeq. This will not override an existing assetsSeq.
+     * @hide
+     */
+    public static final int ASSETS_SEQ_UNDEFINED = 0;
+
+    /**
+     * Internal counter that allows us to piggyback off the configuration change mechanism to
+     * signal to apps that the the assets for an Application have changed. A difference in these
+     * between two Configurations will yield a diff flag of
+     * {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
+     * @hide
+     */
+    public int assetsSeq;
+
+    /**
      * @hide Internal book-keeping.
      */
     public int seq;
@@ -693,6 +776,7 @@
                     NATIVE_CONFIG_UI_MODE,
                     NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
                     NATIVE_CONFIG_LAYOUTDIR,
+                    NATIVE_CONFIG_COLORIMETRY,
             })
     @Retention(RetentionPolicy.SOURCE)
     public @interface NativeConfig {}
@@ -729,6 +813,8 @@
     public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
     /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
     public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
+    /** @hide Native-specific bit mask for COLORIMETRY config ; DO NOT USE UNLESS YOU ARE SURE.*/
+    public static final int NATIVE_CONFIG_COLORIMETRY = 0x10000;
 
     /**
      * <p>Construct an invalid Configuration. This state is only suitable for constructing a
@@ -787,6 +873,7 @@
         navigationHidden = o.navigationHidden;
         orientation = o.orientation;
         screenLayout = o.screenLayout;
+        colorimetry = o.colorimetry;
         uiMode = o.uiMode;
         screenWidthDp = o.screenWidthDp;
         screenHeightDp = o.screenHeightDp;
@@ -795,6 +882,7 @@
         compatScreenWidthDp = o.compatScreenWidthDp;
         compatScreenHeightDp = o.compatScreenHeightDp;
         compatSmallestScreenWidthDp = o.compatSmallestScreenWidthDp;
+        assetsSeq = o.assetsSeq;
         seq = o.seq;
     }
 
@@ -866,6 +954,20 @@
             default: sb.append(" layoutLong=");
                     sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
         }
+        switch ((colorimetry&COLORIMETRY_HDR_MASK)) {
+            case COLORIMETRY_HDR_UNDEFINED: sb.append(" ?ldr"); break; // most likely not HDR
+            case COLORIMETRY_HDR_NO: /* ldr is not interesting to print */ break;
+            case COLORIMETRY_HDR_YES: sb.append(" hdr"); break;
+            default: sb.append(" dynamicRange=");
+                sb.append(colorimetry&COLORIMETRY_HDR_MASK); break;
+        }
+        switch ((colorimetry&COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
+            case COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED: sb.append(" ?wideColorGamut"); break;
+            case COLORIMETRY_WIDE_COLOR_GAMUT_NO: /* not wide is not interesting to print */ break;
+            case COLORIMETRY_WIDE_COLOR_GAMUT_YES: sb.append(" widecg"); break;
+            default: sb.append(" wideColorGamut=");
+                sb.append(colorimetry&COLORIMETRY_WIDE_COLOR_GAMUT_MASK); break;
+        }
         switch (orientation) {
             case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
             case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
@@ -930,9 +1032,11 @@
             case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
             default: sb.append("/"); sb.append(navigationHidden); break;
         }
+        if (assetsSeq != 0) {
+            sb.append(" as.").append(assetsSeq);
+        }
         if (seq != 0) {
-            sb.append(" s.");
-            sb.append(seq);
+            sb.append(" s.").append(seq);
         }
         sb.append('}');
         return sb.toString();
@@ -955,11 +1059,13 @@
         navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
         orientation = ORIENTATION_UNDEFINED;
         screenLayout = SCREENLAYOUT_UNDEFINED;
+        colorimetry = COLORIMETRY_UNDEFINED;
         uiMode = UI_MODE_TYPE_UNDEFINED;
         screenWidthDp = compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED;
         screenHeightDp = compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED;
         smallestScreenWidthDp = compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
         densityDpi = DENSITY_DPI_UNDEFINED;
+        assetsSeq = ASSETS_SEQ_UNDEFINED;
         seq = 0;
     }
 
@@ -1089,6 +1195,23 @@
                 | (delta.screenLayout & SCREENLAYOUT_COMPAT_NEEDED);
         }
 
+        if (((delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
+                     COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED)
+                && (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)
+                != (colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
+            changed |= ActivityInfo.CONFIG_COLORIMETRY;
+            colorimetry = (colorimetry & ~COLORIMETRY_WIDE_COLOR_GAMUT_MASK)
+                    | (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK);
+        }
+
+        if (((delta.colorimetry & COLORIMETRY_HDR_MASK) != COLORIMETRY_HDR_UNDEFINED)
+                && (delta.colorimetry & COLORIMETRY_HDR_MASK)
+                != (colorimetry & COLORIMETRY_HDR_MASK)) {
+            changed |= ActivityInfo.CONFIG_COLORIMETRY;
+            colorimetry = (colorimetry & ~COLORIMETRY_HDR_MASK)
+                    | (delta.colorimetry & COLORIMETRY_HDR_MASK);
+        }
+
         if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED)
                 && uiMode != delta.uiMode) {
             changed |= ActivityInfo.CONFIG_UI_MODE;
@@ -1130,6 +1253,10 @@
         if (delta.compatSmallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
             compatSmallestScreenWidthDp = delta.compatSmallestScreenWidthDp;
         }
+        if (delta.assetsSeq != ASSETS_SEQ_UNDEFINED) {
+            changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
+            assetsSeq = delta.assetsSeq;
+        }
         if (delta.seq != 0) {
             seq = delta.seq;
         }
@@ -1234,6 +1361,19 @@
                 getScreenLayoutNoDirection(delta.screenLayout)) {
             changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT;
         }
+        if ((compareUndefined ||
+                     (delta.colorimetry & COLORIMETRY_HDR_MASK) != COLORIMETRY_HDR_UNDEFINED)
+                && (colorimetry & COLORIMETRY_HDR_MASK) !=
+                        (delta.colorimetry & COLORIMETRY_HDR_MASK)) {
+            changed |= ActivityInfo.CONFIG_COLORIMETRY;
+        }
+        if ((compareUndefined ||
+                     (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
+                             COLORIMETRY_WIDE_COLOR_GAMUT_UNDEFINED)
+                && (colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
+                        (delta.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
+            changed |= ActivityInfo.CONFIG_COLORIMETRY;
+        }
         if ((compareUndefined || delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED))
                 && uiMode != delta.uiMode) {
             changed |= ActivityInfo.CONFIG_UI_MODE;
@@ -1254,6 +1394,10 @@
                 && densityDpi != delta.densityDpi) {
             changed |= ActivityInfo.CONFIG_DENSITY;
         }
+        if ((compareUndefined || delta.assetsSeq != ASSETS_SEQ_UNDEFINED)
+                && assetsSeq != delta.assetsSeq) {
+            changed |= ActivityInfo.CONFIG_ASSETS_PATHS;
+        }
 
         return changed;
     }
@@ -1272,7 +1416,11 @@
      */
     public static boolean needNewResources(@Config int configChanges,
             @Config int interestingChanges) {
-        return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
+        // CONFIG_ASSETS_PATHS and CONFIG_FONT_SCALE are higher level configuration changes that
+        // all resources are subject to change with.
+        interestingChanges = interestingChanges | ActivityInfo.CONFIG_ASSETS_PATHS
+                | ActivityInfo.CONFIG_FONT_SCALE;
+        return (configChanges & interestingChanges) != 0;
     }
 
     /**
@@ -1337,6 +1485,7 @@
         dest.writeInt(navigationHidden);
         dest.writeInt(orientation);
         dest.writeInt(screenLayout);
+        dest.writeInt(colorimetry);
         dest.writeInt(uiMode);
         dest.writeInt(screenWidthDp);
         dest.writeInt(screenHeightDp);
@@ -1345,6 +1494,7 @@
         dest.writeInt(compatScreenWidthDp);
         dest.writeInt(compatScreenHeightDp);
         dest.writeInt(compatSmallestScreenWidthDp);
+        dest.writeInt(assetsSeq);
         dest.writeInt(seq);
     }
 
@@ -1370,6 +1520,7 @@
         navigationHidden = source.readInt();
         orientation = source.readInt();
         screenLayout = source.readInt();
+        colorimetry = source.readInt();
         uiMode = source.readInt();
         screenWidthDp = source.readInt();
         screenHeightDp = source.readInt();
@@ -1378,6 +1529,7 @@
         compatScreenWidthDp = source.readInt();
         compatScreenHeightDp = source.readInt();
         compatSmallestScreenWidthDp = source.readInt();
+        assetsSeq = source.readInt();
         seq = source.readInt();
     }
 
@@ -1450,6 +1602,8 @@
         if (n != 0) return n;
         n = this.orientation - that.orientation;
         if (n != 0) return n;
+        n = this.colorimetry - that.colorimetry;
+        if (n != 0) return n;
         n = this.screenLayout - that.screenLayout;
         if (n != 0) return n;
         n = this.uiMode - that.uiMode;
@@ -1461,6 +1615,8 @@
         n = this.smallestScreenWidthDp - that.smallestScreenWidthDp;
         if (n != 0) return n;
         n = this.densityDpi - that.densityDpi;
+        if (n != 0) return n;
+        n = this.assetsSeq - that.assetsSeq;
         //if (n != 0) return n;
         return n;
     }
@@ -1493,11 +1649,13 @@
         result = 31 * result + navigationHidden;
         result = 31 * result + orientation;
         result = 31 * result + screenLayout;
+        result = 31 * result + colorimetry;
         result = 31 * result + uiMode;
         result = 31 * result + screenWidthDp;
         result = 31 * result + screenHeightDp;
         result = 31 * result + smallestScreenWidthDp;
         result = 31 * result + densityDpi;
+        result = 31 * result + assetsSeq;
         return result;
     }
 
@@ -1600,6 +1758,24 @@
     }
 
     /**
+     * Return whether the screen has a wide color gamut.
+     *
+     * @return true if the screen has a wide color gamut, false otherwise
+     */
+    public boolean isScreenWideColorGamut() {
+        return (colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) == COLORIMETRY_WIDE_COLOR_GAMUT_YES;
+    }
+
+    /**
+     * Return whether the screen has a high dynamic range.
+     *
+     * @return true if the screen has a high dynamic range, false otherwise
+     */
+    public boolean isScreenHdr() {
+        return (colorimetry & COLORIMETRY_HDR_MASK) == COLORIMETRY_HDR_YES;
+    }
+
+    /**
      *
      * @hide
      */
@@ -1731,6 +1907,28 @@
                 break;
         }
 
+        switch (config.colorimetry & Configuration.COLORIMETRY_HDR_MASK) {
+            case Configuration.COLORIMETRY_HDR_YES:
+                parts.add("highdr");
+                break;
+            case Configuration.COLORIMETRY_HDR_NO:
+                parts.add("lowdr");
+                break;
+            default:
+                break;
+        }
+
+        switch (config.colorimetry & Configuration.COLORIMETRY_WIDE_COLOR_GAMUT_MASK) {
+            case Configuration.COLORIMETRY_WIDE_COLOR_GAMUT_YES:
+                parts.add("widecg");
+                break;
+            case Configuration.COLORIMETRY_WIDE_COLOR_GAMUT_NO:
+                parts.add("nowidecg");
+                break;
+            default:
+                break;
+        }
+
         switch (config.orientation) {
             case Configuration.ORIENTATION_LANDSCAPE:
                 parts.add("land");
@@ -1956,6 +2154,16 @@
             delta.screenLayout |= change.screenLayout & SCREENLAYOUT_ROUND_MASK;
         }
 
+        if ((base.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK) !=
+                (change.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK)) {
+            delta.colorimetry |= change.colorimetry & COLORIMETRY_WIDE_COLOR_GAMUT_MASK;
+        }
+
+        if ((base.colorimetry & COLORIMETRY_HDR_MASK) !=
+                (change.colorimetry & COLORIMETRY_HDR_MASK)) {
+            delta.colorimetry |= change.colorimetry & COLORIMETRY_HDR_MASK;
+        }
+
         if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) {
             delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK;
         }
@@ -1979,6 +2187,10 @@
         if (base.densityDpi != change.densityDpi) {
             delta.densityDpi = change.densityDpi;
         }
+
+        if (base.assetsSeq != change.assetsSeq) {
+            delta.assetsSeq = change.assetsSeq;
+        }
         return delta;
     }
 
@@ -1994,6 +2206,7 @@
     private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid";
     private static final String XML_ATTR_ORIENTATION = "ori";
     private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay";
+    private static final String XML_ATTR_COLORIMETRY = "clrMtry";
     private static final String XML_ATTR_UI_MODE = "ui";
     private static final String XML_ATTR_SCREEN_WIDTH = "width";
     private static final String XML_ATTR_SCREEN_HEIGHT = "height";
@@ -2036,6 +2249,8 @@
                 ORIENTATION_UNDEFINED);
         configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT,
                 SCREENLAYOUT_UNDEFINED);
+        configOut.colorimetry = XmlUtils.readIntAttribute(parser, XML_ATTR_COLORIMETRY,
+                COLORIMETRY_UNDEFINED);
         configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0);
         configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH,
                 SCREEN_WIDTH_DP_UNDEFINED);
@@ -2046,6 +2261,8 @@
                         SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
         configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY,
                 DENSITY_DPI_UNDEFINED);
+
+        // For persistence, we don't care about assetsSeq, so do not read it out.
     }
 
 
@@ -2096,6 +2313,9 @@
         if (config.screenLayout != SCREENLAYOUT_UNDEFINED) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_LAYOUT, config.screenLayout);
         }
+        if (config.colorimetry != COLORIMETRY_UNDEFINED) {
+            XmlUtils.writeIntAttribute(xml, XML_ATTR_COLORIMETRY, config.colorimetry);
+        }
         if (config.uiMode != 0) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_UI_MODE, config.uiMode);
         }
@@ -2111,5 +2331,7 @@
         if (config.densityDpi != DENSITY_DPI_UNDEFINED) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_DENSITY, config.densityDpi);
         }
+
+        // For persistence, we do not care about assetsSeq, so do not write it out.
     }
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ad11307..c3185a7 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -40,6 +40,7 @@
 import android.annotation.XmlRes;
 import android.content.pm.ActivityInfo;
 import android.graphics.Movie;
+import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.DrawableInflater;
@@ -333,7 +334,35 @@
             return res;
         }
         throw new NotFoundException("String resource ID #0x"
-                                    + Integer.toHexString(id));
+                + Integer.toHexString(id));
+    }
+
+    /**
+     * Return the Typeface value associated with a particular resource ID.
+     * {@more}
+     *
+     * @param id The desired resource identifier, as generated by the aapt
+     *           tool. This integer encodes the package, type, and resource
+     *           entry. The value 0 is an invalid identifier.
+     *
+     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
+     *
+     * @return Typeface The Typeface data associated with the resource.
+     */
+    @NonNull public Typeface getFont(@StringRes int id) throws NotFoundException {
+        final TypedValue value = obtainTempTypedValue();
+        try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
+            Typeface typeface = impl.loadFont(value, id);
+            if (typeface != null) {
+                return typeface;
+            }
+        } finally {
+            releaseTempTypedValue(value);
+        }
+        throw new NotFoundException("Font resource ID #0x"
+                + Integer.toHexString(id));
     }
 
     /**
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index eb010e4..05892e0 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -31,6 +31,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.NotFoundException;
+import android.graphics.Typeface;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.icu.text.PluralRules;
@@ -47,6 +48,7 @@
 import android.view.Display;
 import android.view.DisplayAdjustments;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
 import java.util.Locale;
@@ -740,6 +742,36 @@
     }
 
     /**
+     * Loads a font from XML or resources stream.
+     */
+    @Nullable
+    public Typeface loadFont(TypedValue value, int id) {
+        if (value.string == null) {
+            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+                    + Integer.toHexString(id) + ") is not a Font: " + value);
+        }
+
+        final String file = value.string.toString();
+
+        if (DEBUG_LOAD) {
+            Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file);
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        try {
+            if (file.endsWith(".xml")) {
+                // TODO handle xml type font definitions
+            } else {
+                return Typeface.createFromResources(
+                        mAssets, value.string.toString(), value.assetCookie);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+        }
+        return null;
+    }
+
+    /**
      * Given the value and id, we can get the XML filename as in value.data, based on that, we
      * first try to load CSL from the cache. If not found, try to get from the constant state.
      * Last, parse the XML and generate the CSL.
diff --git a/core/java/android/hardware/HardwareBuffer.aidl b/core/java/android/hardware/HardwareBuffer.aidl
new file mode 100644
index 0000000..5bdd966
--- /dev/null
+++ b/core/java/android/hardware/HardwareBuffer.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.hardware;
+
+parcelable HardwareBuffer;
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
new file mode 100644
index 0000000..fffb1d7
--- /dev/null
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -0,0 +1,318 @@
+/*
+ * 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.hardware;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import dalvik.annotation.optimization.FastNative;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * HardwareBuffer wraps a native <code>AHardwareBuffer</code> object, which is a low-level object
+ * representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing
+ * buffers across different application processes. In particular, HardwareBuffers may be mappable
+ * to memory accessibly to various hardware systems, such as the GPU, a sensor or context hub, or
+ * other auxiliary processing units.
+ *
+ * For more information, see the NDK documentation for <code>AHardwareBuffer</code>.
+ */
+public final class HardwareBuffer implements Parcelable {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({RGBA_8888, RGBA_FP16, RGBX_8888, RGB_888, RGB_565})
+    public @interface Format {};
+
+    /** Format: 8 bits each red, green, blue, alpha */
+    public static final int RGBA_8888   = 1;
+    /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
+    public static final int RGBX_8888   = 2;
+    /** Format: 8 bits each red, green, blue, no alpha */
+    public static final int RGB_888     = 3;
+    /** Format: 5 bits each red and blue, 6 bits green, no alpha */
+    public static final int RGB_565     = 4;
+    /** Format: 16 bits each red, green, blue, alpha */
+    public static final int RGBA_FP16   = 5;
+
+    // Note: do not rename, this field is used by native code
+    private long mNativeObject;
+
+    // Invoked on destruction
+    private Runnable mCleaner;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, value = {USAGE0_CPU_READ, USAGE0_CPU_READ_OFTEN, USAGE0_CPU_WRITE,
+            USAGE0_CPU_WRITE_OFTEN, USAGE0_GPU_SAMPLED_IMAGE, USAGE0_GPU_COLOR_OUTPUT,
+            USAGE0_GPU_STORAGE_IMAGE, USAGE0_GPU_CUBEMAP, USAGE0_GPU_DATA_BUFFER,
+            USAGE0_PROTECTED_CONTENT, USAGE0_SENSOR_DIRECT_DATA, USAGE0_VIDEO_ENCODE})
+    public @interface Usage0 {};
+
+    /** Usage0: the buffer will sometimes be read by the CPU */
+    public static final long USAGE0_CPU_READ               = (1 << 1);
+    /** Usage0: the buffer will often be read by the CPU*/
+    public static final long USAGE0_CPU_READ_OFTEN         = (1 << 2 | USAGE0_CPU_READ);
+    /** Usage0: the buffer will sometimes be written to by the CPU */
+    public static final long USAGE0_CPU_WRITE              = (1 << 5);
+    /** Usage0: the buffer will often be written to by the CPU */
+    public static final long USAGE0_CPU_WRITE_OFTEN        = (1 << 6 | USAGE0_CPU_WRITE);
+    /** Usage0: the buffer will be read from by the GPU */
+    public static final long USAGE0_GPU_SAMPLED_IMAGE      = (1 << 10);
+    /** Usage0: the buffer will be written to by the GPU */
+    public static final long USAGE0_GPU_COLOR_OUTPUT       = (1 << 11);
+    /** Usage0: the buffer will be read from and written to by the GPU */
+    public static final long USAGE0_GPU_STORAGE_IMAGE      = (USAGE0_GPU_SAMPLED_IMAGE |
+            USAGE0_GPU_COLOR_OUTPUT);
+    /** Usage0: the buffer will be used as a cubemap texture */
+    public static final long USAGE0_GPU_CUBEMAP            = (1 << 13);
+    /** Usage0: the buffer will be used as a shader storage or uniform buffer object*/
+    public static final long USAGE0_GPU_DATA_BUFFER        = (1 << 14);
+    /** Usage0: the buffer must not be used outside of a protected hardware path */
+    public static final long USAGE0_PROTECTED_CONTENT      = (1 << 18);
+    /** Usage0: the buffer will be used for sensor direct data */
+    public static final long USAGE0_SENSOR_DIRECT_DATA     = (1 << 29);
+    /** Usage0: the buffer will be read by a hardware video encoder */
+    public static final long USAGE0_VIDEO_ENCODE           = (1 << 21);
+
+    // The approximate size of a native AHardwareBuffer object.
+    private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
+    /**
+     * Creates a new <code>HardwareBuffer</code> instance.
+     *
+     * <p>Calling this method will throw an <code>IllegalStateException</code> if
+     * format is not a supported Format type.</p>
+     *
+     * @param width The width in pixels of the buffer
+     * @param height The height in pixels of the buffer
+     * @param format The format of each pixel, one of {@link #RGBA_8888}, {@link #RGBA_FP16},
+     * {@link #RGBX_8888}, {@link #RGB_565}, {@link #RGB_888}
+     * @param layers The number of layers in the buffer
+     * @param usage Flags describing how the buffer will be used, one of
+     *     {@link #USAGE0_CPU_READ}, {@link #USAGE0_CPU_READ_OFTEN}, {@link #USAGE0_CPU_WRITE},
+     *     {@link #USAGE0_CPU_WRITE_OFTEN}, {@link #USAGE0_GPU_SAMPLED_IMAGE},
+     *     {@link #USAGE0_GPU_COLOR_OUTPUT},{@link #USAGE0_GPU_STORAGE_IMAGE},
+     *     {@link #USAGE0_GPU_CUBEMAP}, {@link #USAGE0_GPU_DATA_BUFFER},
+     *     {@link #USAGE0_PROTECTED_CONTENT}, {@link #USAGE0_SENSOR_DIRECT_DATA},
+     *     {@link #USAGE0_VIDEO_ENCODE}
+     *
+     * @return A <code>HardwareBuffer</code> instance if successful, or throws an
+     *     IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
+     *     too large to allocate), if the format is not supported, if the requested number of layers
+     *     is less than one or not supported, or if the passed usage flags are not a supported set.
+     */
+    @NonNull
+    public static HardwareBuffer create(int width, int height, @Format int format, int layers,
+            @Usage0 long usage) {
+        if (!HardwareBuffer.isSupportedFormat(format)) {
+            throw new IllegalArgumentException("Invalid pixel format " + format);
+        }
+        if (width <= 0) {
+            throw new IllegalArgumentException("Invalid width " + width);
+        }
+        if (height <= 0) {
+            throw new IllegalArgumentException("Invalid height " + height);
+        }
+        if (layers <= 0) {
+            throw new IllegalArgumentException("Invalid layer count " + layers);
+        }
+        long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage);
+        if (nativeObject == 0) {
+            throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
+                    "dimensions passed were too large, too many image layers were requested, " +
+                    "or an invalid set of usage flags was passed");
+        }
+        return new HardwareBuffer(nativeObject);
+    }
+
+    /**
+     * Private use only. See {@link #create(int, int, int, int, int, long, long)}. May also be
+     * called from JNI using an already allocated native <code>HardwareBuffer</code>.
+     */
+    private HardwareBuffer(long nativeObject) {
+        mNativeObject = nativeObject;
+
+        long nativeSize = NATIVE_HARDWARE_BUFFER_SIZE;
+        NativeAllocationRegistry registry = new NativeAllocationRegistry(
+            HardwareBuffer.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
+        mCleaner = registry.registerNativeAllocation(this, mNativeObject);
+    }
+
+    /**
+     * Returns the width of this buffer in pixels.
+     */
+    public int getWidth() {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("This HardwareBuffer has been destroyed and its width "
+                    + "cannot be obtained.");
+        }
+        return nGetWidth(mNativeObject);
+    }
+
+    /**
+     * Returns the height of this buffer in pixels.
+     */
+    public int getHeight() {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("This HardwareBuffer has been destroyed and its height "
+                    + "cannot be obtained.");
+        }
+        return nGetHeight(mNativeObject);
+    }
+
+    /**
+     * Returns the format of this buffer, one of {@link #RGBA_8888}, {@link #RGBA_FP16},
+     * {@link #RGBX_8888}, {@link #RGB_565}, or {@link #RGB_888}.
+     */
+    public int getFormat() {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("This HardwareBuffer has been destroyed and its format "
+                    + "cannot be obtained.");
+        }
+        return nGetFormat(mNativeObject);
+    }
+
+    /**
+     * Returns the number of layers in this buffer.
+     */
+    public int getLayers() {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("This HardwareBuffer has been destroyed and its layer "
+                    + "count cannot be obtained.");
+        }
+        return nGetLayers(mNativeObject);
+    }
+
+    /**
+     * Returns the usage flags of the usage hints set on this buffer.
+     */
+    public long getUsage() {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("This HardwareBuffer has been destroyed and its usage "
+                    + "cannot be obtained.");
+        }
+        return nGetUsage(mNativeObject);
+    }
+
+    /**
+     * Destroys this buffer immediately. Calling this method frees up any
+     * underlying native resources. After calling this method, this buffer
+     * must not be used in any way.
+     *
+     * @see #isDestroyed()
+     */
+    public void destroy() {
+        if (mNativeObject != 0) {
+            mNativeObject = 0;
+            mCleaner.run();
+            mCleaner = null;
+        }
+    }
+
+    /**
+     * Indicates whether this buffer has been destroyed. A destroyed buffer
+     * cannot be used in any way: the buffer cannot be written to a parcel, etc.
+     *
+     * @return True if this <code>HardwareBuffer</code> is in a destroyed state,
+     *         false otherwise.
+     *
+     * @see #destroy()
+     */
+    public boolean isDestroyed() {
+        return mNativeObject == 0;
+    }
+
+    @Override
+    public int describeContents() {
+        return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+    }
+
+    /**
+     * Flatten this object in to a Parcel.
+     *
+     * <p>Calling this method will throw an <code>IllegalStateException</code> if
+     * {@link #destroy()} has been previously called.</p>
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mNativeObject == 0) {
+            throw new IllegalStateException("This HardwareBuffer has been destroyed and cannot be "
+                    + "written to a parcel.");
+        }
+        nWriteHardwareBufferToParcel(mNativeObject, dest);
+    }
+
+    public static final Parcelable.Creator<HardwareBuffer> CREATOR =
+            new Parcelable.Creator<HardwareBuffer>() {
+        public HardwareBuffer createFromParcel(Parcel in) {
+            long nativeObject = nReadHardwareBufferFromParcel(in);
+            if (nativeObject != 0) {
+                return new HardwareBuffer(nativeObject);
+            }
+            return null;
+        }
+
+        public HardwareBuffer[] newArray(int size) {
+            return new HardwareBuffer[size];
+        }
+    };
+
+    /**
+     * Validates whether a particular format is supported by HardwareBuffer.
+     *
+     * @param format The format to validate.
+     *
+     * @return True if <code>format</code> is a supported format. false otherwise.
+     * See {@link #create(int, int, int, int, int, long, long)}.a
+     */
+    private static boolean isSupportedFormat(@Format int format) {
+        switch(format) {
+            case RGBA_8888:
+            case RGBA_FP16:
+            case RGBX_8888:
+            case RGB_565:
+            case RGB_888:
+                return true;
+        }
+        return false;
+    }
+
+    private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
+            long usage);
+    private static native long nGetNativeFinalizer();
+    private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
+    private static native long nReadHardwareBufferFromParcel(Parcel in);
+    @FastNative
+    private static native int nGetWidth(long nativeObject);
+    @FastNative
+    private static native int nGetHeight(long nativeObject);
+    @FastNative
+    private static native int nGetFormat(long nativeObject);
+    @FastNative
+    private static native int nGetLayers(long nativeObject);
+    @FastNative
+    private static native long nGetUsage(long nativeObject);
+}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 04ee1e6..3ccac69 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -492,7 +492,7 @@
         if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
                 type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
                 type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
-                type == Sensor.TYPE_WRIST_TILT_GESTURE) {
+                type == Sensor.TYPE_WRIST_TILT_GESTURE || type == Sensor.TYPE_DYNAMIC_SENSOR_META) {
             wakeUpSensor = true;
         }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 5e9fd66..4befb29 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -48,8 +48,6 @@
 
     /** Input surface configured by native camera framework based on user-specified configuration */
     private final Surface mInput;
-    /** User-specified set of surfaces used as the configuration outputs */
-    private final List<Surface> mOutputs;
     /**
      * User-specified state callback, used for outgoing events; calls to this object will be
      * automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}.
@@ -87,21 +85,17 @@
      * There must be no pending actions
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
-    CameraCaptureSessionImpl(int id, Surface input, List<Surface> outputs,
+    CameraCaptureSessionImpl(int id, Surface input,
             CameraCaptureSession.StateCallback callback, Handler stateHandler,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess) {
-        if (outputs == null || outputs.isEmpty()) {
-            throw new IllegalArgumentException("outputs must be a non-null, non-empty list");
-        } else if (callback == null) {
+        if (callback == null) {
             throw new IllegalArgumentException("callback must not be null");
         }
 
         mId = id;
         mIdString = String.format("Session %d: ", mId);
 
-        // TODO: extra verification of outputs
-        mOutputs = outputs;
         mInput = input;
         mStateHandler = checkHandler(stateHandler);
         mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 4481a74..01e58f4 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -58,14 +58,14 @@
      * There must be no pending actions
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
-    CameraConstrainedHighSpeedCaptureSessionImpl(int id, List<Surface> outputs,
+    CameraConstrainedHighSpeedCaptureSessionImpl(int id,
             CameraCaptureSession.StateCallback callback, Handler stateHandler,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess,
             CameraCharacteristics characteristics) {
         mCharacteristics = characteristics;
         CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
-        mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, outputs, wrapperCallback,
+        mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
                 stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
     }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 97ca56ef..d2aeaea 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -501,7 +501,7 @@
             CameraCaptureSession.StateCallback callback, Handler handler)
             throws CameraAccessException {
         if (DEBUG) {
-            Log.d(TAG, "createCaptureSessionByOutputConfiguration");
+            Log.d(TAG, "createCaptureSessionByOutputConfigurations");
         }
 
         // OutputConfiguration objects are immutable, but need to have our own array
@@ -621,19 +621,15 @@
                 }
             }
 
-            List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
-            for (OutputConfiguration config : outputConfigurations) {
-                outSurfaces.add(config.getSurface());
-            }
             // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
             CameraCaptureSessionCore newSession = null;
             if (isConstrainedHighSpeed) {
                 newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
-                        outSurfaces, callback, handler, this, mDeviceHandler, configureSuccess,
+                        callback, handler, this, mDeviceHandler, configureSuccess,
                         mCharacteristics);
             } else {
                 newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
-                        outSurfaces, callback, handler, this, mDeviceHandler,
+                        callback, handler, this, mDeviceHandler,
                         configureSuccess);
             }
 
@@ -1946,24 +1942,33 @@
 
             Runnable failureDispatch = null;
             if (errorCode == ERROR_CAMERA_BUFFER) {
-                final Surface outputSurface =
-                        mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurface();
-                if (DEBUG) {
-                    Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s",
-                            frameNumber, outputSurface));
-                }
-                failureDispatch = new Runnable() {
-                    @Override
-                    public void run() {
-                        if (!CameraDeviceImpl.this.isClosed()){
-                            holder.getCallback().onCaptureBufferLost(
-                                CameraDeviceImpl.this,
-                                request,
-                                outputSurface,
-                                frameNumber);
-                        }
+                // Because 1 stream id could map to multiple surfaces, we need to specify both
+                // streamId and surfaceId.
+                List<Surface> surfaces =
+                        mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurfaces();
+                for (Surface surface : surfaces) {
+                    if (!request.containsTarget(surface)) {
+                        continue;
                     }
-                };
+                    if (DEBUG) {
+                        Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s",
+                                frameNumber, surface));
+                    }
+                    failureDispatch = new Runnable() {
+                        @Override
+                        public void run() {
+                            if (!CameraDeviceImpl.this.isClosed()){
+                                holder.getCallback().onCaptureBufferLost(
+                                    CameraDeviceImpl.this,
+                                    request,
+                                    surface,
+                                    frameNumber);
+                            }
+                        }
+                    };
+                    // Dispatch the failure callback
+                    holder.getHandler().post(failureDispatch);
+                }
             } else {
                 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
 
@@ -2000,10 +2005,11 @@
                 }
                 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess());
                 checkAndFireSequenceComplete();
+
+                // Dispatch the failure callback
+                holder.getHandler().post(failureDispatch);
             }
 
-            // Dispatch the failure callback
-            holder.getHandler().post(failureDispatch);
         }
 
     } // public class CameraDeviceCallbacks
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index f897d85..4654fc2 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -31,13 +31,17 @@
 import android.util.Size;
 import android.view.Surface;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
+
 import static com.android.internal.util.Preconditions.*;
 
 /**
  * A class for describing camera output, which contains a {@link Surface} and its specific
  * configuration for creating capture session.
  *
- * @see CameraDevice#createCaptureSessionByOutputConfiguration
+ * @see CameraDevice#createCaptureSessionByOutputConfigurations
  *
  */
 public final class OutputConfiguration implements Parcelable {
@@ -147,6 +151,50 @@
     }
 
     /**
+     * Create a new {@link OutputConfiguration} instance with two surfaces sharing the same stream,
+     * with a surface group ID.
+     *
+     * <p>For advanced use cases, a camera application may require more streams than the combination
+     * guaranteed by {@link CameraDevice#createCaptureSession}. In this case, two compatible
+     * surfaces can be attached to one OutputConfiguration so that they map to one camera stream,
+     * and buffers are reference counted when being consumed by both surfaces. </p>
+     *
+     * <p>Two surfaces are compatible in below 2 cases:</p>
+     *
+     * <ol>
+     * <li> Surfaces with the same size, format, dataSpace, and Surface source class. In this case,
+     * {@link CameraDevice#createCaptureSessionByOutputConfigurations} is guaranteed to succeed.
+     *
+     * <li> Surfaces with the same size, format, and dataSpace, but different Surface
+     * source classes. However, on some devices, the underlying camera device is able to use the
+     * same buffer layout for both surfaces. The only way to discover if this is the case is to
+     * create a capture session with that output configuration. For example, if the camera device
+     * uses the same private buffer format between a SurfaceView/SurfaceTexture and a
+     * MediaRecorder/MediaCodec, {@link CameraDevice#createCaptureSessionByOutputConfigurations}
+     * will succeed. Otherwise, it throws {@code IllegalArgumentException}.
+     * </ol>
+     *
+     * @param surfaceGroupId
+     *          A group ID for this output, used for sharing memory between multiple outputs.
+     * @param surface
+     *          A Surface for camera to output to.
+     * @param surface2
+     *          Second surface for camera to output to.
+     * @throws IllegalArgumentException if the two surfaces have different size, format, or
+     * dataSpace.
+     *
+     * @hide
+     */
+    public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface,
+            @NonNull Surface surface2) {
+        this(surfaceGroupId, surface, ROTATION_0, surface2);
+
+        checkNotNull(surface2, "Surface must not be null");
+        checkMatchingSurfaces(mConfiguredSize, mConfiguredFormat, mConfiguredDataspace,
+                mConfiguredGenerationId, surface2);
+    }
+
+    /**
      * Create a new {@link OutputConfiguration} instance.
      *
      * <p>This constructor takes an argument for desired camera rotation</p>
@@ -169,7 +217,6 @@
         this(SURFACE_GROUP_ID_NONE, surface, rotation);
     }
 
-
     /**
      * Create a new {@link OutputConfiguration} instance, with rotation and a group ID.
      *
@@ -193,17 +240,68 @@
      */
     @SystemApi
     public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
+        this(surfaceGroupId, surface, rotation, null /*surface2*/);
+    }
+
+    /**
+     * Create a new {@link OutputConfiguration} instance, with rotation, a group ID, and a secondary
+     * surface.
+     *
+     * <p>This constructor takes an argument for desired camera rotation, the surface group
+     * ID, and a secondary surface.  See {@link #OutputConfiguration(int, Surface)} for details
+     * of the group ID.</p>
+     *
+     * <p>surface2 should be compatible with surface. See {@link #OutputConfiguration(int, Surface,
+     * Surface} for details of compatibility between surfaces.</p>
+     *
+     * <p>Since the rotation is done by the CameraDevice, both surfaces will receive buffers with
+     * the same rotation applied. This means that if the application needs two compatible surfaces
+     * to have different rotations, these surfaces cannot be shared within one OutputConfiguration.
+     * </p>
+     *
+     * @param surfaceGroupId
+     *          A group ID for this output, used for sharing memory between multiple outputs.
+     * @param surface
+     *          A Surface for camera to output to.
+     * @param rotation
+     *          The desired rotation to be applied on camera output. Value must be one of
+     *          ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
+     *          application should make sure corresponding surface size has width and height
+     *          transposed relative to the width and height without rotation. For example,
+     *          if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
+     *          application should set rotation to {@code ROTATION_90} and make sure the
+     *          corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
+     *          throw {@code IllegalArgumentException} if device cannot perform such rotation.
+     * @param surface2
+     *          Second surface for camera to output to.
+
+     * @throws IllegalArgumentException if the two surfaces are not compatible to be shared in
+     *                                  one OutputConfiguration.
+     *
+     * @hide
+     */
+    private OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation,
+            @Nullable Surface surface2) {
         checkNotNull(surface, "Surface must not be null");
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+
         mSurfaceGroupId = surfaceGroupId;
         mSurfaceType = SURFACE_TYPE_UNKNOWN;
-        mSurface = surface;
         mRotation = rotation;
         mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
         mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
         mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
         mConfiguredGenerationId = surface.getGenerationId();
         mIsDeferredConfig = false;
+
+        if (surface2 == null) {
+            mSurfaces = new Surface[1];
+            mSurfaces[0] = surface;
+        } else {
+            mSurfaces = new Surface[MAX_SURFACES_COUNT];
+            mSurfaces[0] = surface;
+            mSurfaces[1] = surface2;
+        }
     }
 
     /**
@@ -231,25 +329,34 @@
      *            {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
      */
     public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass) {
-        checkNotNull(klass, "surfaceSize must not be null");
-        checkNotNull(klass, "klass must not be null");
-        if (klass == android.view.SurfaceHolder.class) {
-            mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
-        } else if (klass == android.graphics.SurfaceTexture.class) {
-            mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
-        } else {
-            mSurfaceType = SURFACE_TYPE_UNKNOWN;
-            throw new IllegalArgumentException("Unknow surface source class type");
-        }
+        this(surfaceSize, klass, true /* dummy */);
 
-        mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
-        mSurface = null;
-        mRotation = ROTATION_0;
-        mConfiguredSize = surfaceSize;
-        mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
-        mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
-        mConfiguredGenerationId = 0;
-        mIsDeferredConfig = true;
+        mSurfaces = new Surface[1];
+    }
+
+    /**
+     * Create a new {@link OutputConfiguration} instance, with desired Surface size and Surface
+     * source class for the deferred surface, and a secondary surface.
+     *
+     * <p>This constructor takes an argument for desired surface size and surface source class of
+     * the deferred surface, and a secondary surface. See {@link #OutputConfiguration(Size, Class)}
+     * for details of the surface size and surface source class.</p>
+     *
+     * <p> The deferred surface and secondary surface should be compatible. See
+     * {@link #OutputConfiguration(int, Surface, Surface)} for details of compatible surfaces.
+     *
+     * @hide
+     */
+    public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass,
+            @NonNull Surface surface2) {
+        this(surfaceSize, klass, true /* dummy */);
+
+        checkMatchingSurfaces(mConfiguredSize, mConfiguredFormat, mConfiguredDataspace,
+                mConfiguredGenerationId, surface2);
+
+        mSurfaces = new Surface[MAX_SURFACES_COUNT];
+        mSurfaces[0] = null;
+        mSurfaces[1] = surface2;
     }
 
     /**
@@ -285,7 +392,7 @@
      */
     public void setDeferredSurface(@NonNull Surface surface) {
         checkNotNull(surface, "Surface must not be null");
-        if (mSurface != null) {
+        if (mSurfaces[0] != null) {
             throw new IllegalStateException("Deferred surface is already set!");
         }
 
@@ -297,7 +404,7 @@
                     ", the pre-configured size will be used.");
         }
 
-        mSurface = surface;
+        mSurfaces[0] = surface;
     }
 
     /**
@@ -313,7 +420,7 @@
             throw new IllegalArgumentException("OutputConfiguration shouldn't be null");
         }
 
-        this.mSurface = other.mSurface;
+        this.mSurfaces = other.mSurfaces;
         this.mRotation = other.mRotation;
         this.mSurfaceGroupId = other.mSurfaceGroupId;
         this.mSurfaceType = other.mSurfaceType;
@@ -325,6 +432,49 @@
     }
 
     /**
+     * Private constructor to initialize Configuration based on surface size and class
+     */
+    private <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass,
+            boolean dummy) {
+        checkNotNull(surfaceSize, "surfaceSize must not be null");
+        checkNotNull(klass, "klass must not be null");
+        if (klass == android.view.SurfaceHolder.class) {
+            mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
+        } else if (klass == android.graphics.SurfaceTexture.class) {
+            mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
+        } else {
+            mSurfaceType = SURFACE_TYPE_UNKNOWN;
+            throw new IllegalArgumentException("Unknow surface source class type");
+        }
+
+        mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
+        mRotation = ROTATION_0;
+        mConfiguredSize = surfaceSize;
+        mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
+        mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+        mConfiguredGenerationId = 0;
+        mIsDeferredConfig = true;
+    }
+
+    /**
+     * Check if the surface properties match that of the given surface.
+     *
+     * @return true if the properties and the surface match.
+     */
+    private void checkMatchingSurfaces(Size size, int format, int dataSpace, int generationId,
+            @NonNull Surface surface) {
+        if (!size.equals(SurfaceUtils.getSurfaceSize(surface))) {
+            throw new IllegalArgumentException("Secondary surface size doesn't match");
+        }
+        if (dataSpace != SurfaceUtils.getSurfaceDataspace(surface)) {
+            throw new IllegalArgumentException("Secondary surface dataspace doesn't match");
+        }
+        if (format != SurfaceUtils.getSurfaceFormat(surface)) {
+            throw new IllegalArgumentException("Secondary surface format doesn't match");
+        }
+    }
+
+    /**
      * Create an OutputConfiguration from Parcel.
      */
     private OutputConfiguration(@NonNull Parcel source) {
@@ -333,25 +483,52 @@
         int surfaceType = source.readInt();
         int width = source.readInt();
         int height = source.readInt();
-        Surface surface = Surface.CREATOR.createFromParcel(source);
+        int surfaceCnt = source.readInt();
+
+        if (surfaceCnt <= 0) {
+            throw new IllegalArgumentException(
+                    "Surface count in OutputConfiguration must be greater than 0");
+        }
+        if (surfaceCnt > MAX_SURFACES_COUNT) {
+            throw new IllegalArgumentException(
+                    "Surface count in OutputConfiguration must not be more than "
+                    + MAX_SURFACES_COUNT);
+        }
+
+        Surface[] surfaces = new Surface[surfaceCnt];
+        for (int i = 0; i < surfaceCnt; i++) {
+            Surface surface = Surface.CREATOR.createFromParcel(source);
+            surfaces[i] = surface;
+
+            if (surface == null && i > 0) {
+                throw new IllegalArgumentException("Only the first surface can be deferred");
+            }
+        }
+
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+
         mSurfaceGroupId = surfaceSetId;
-        mSurface = surface;
         mRotation = rotation;
-        if (surface != null) {
+        mSurfaces = surfaces;
+        mConfiguredSize = new Size(width, height);
+        // First surface could be null (being deferred). Use last surface to look up surface
+        // characteristics.
+        if (mSurfaces[surfaceCnt-1] != null) {
             mSurfaceType = SURFACE_TYPE_UNKNOWN;
-            mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
-            mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
-            mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
-            mConfiguredGenerationId = mSurface.getGenerationId();
-            mIsDeferredConfig = true;
+            mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurfaces[surfaceCnt-1]);
+            mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurfaces[surfaceCnt-1]);
+            mConfiguredGenerationId = mSurfaces[surfaceCnt-1].getGenerationId();
         } else {
             mSurfaceType = surfaceType;
-            mConfiguredSize = new Size(width, height);
             mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
-            mConfiguredGenerationId = 0;
             mConfiguredDataspace =
                     StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+            mConfiguredGenerationId = 0;
+        }
+
+        if (mSurfaces[0] == null) {
+            mIsDeferredConfig = true;
+        } else {
             mIsDeferredConfig = false;
         }
     }
@@ -359,11 +536,27 @@
     /**
      * Get the {@link Surface} associated with this {@link OutputConfiguration}.
      *
-     * @return the {@link Surface} associated with this {@link OutputConfiguration}.
+     * @return the {@link Surface} associated with this {@link OutputConfiguration}. If more than
+     * one surface is associated with this {@link OutputConfiguration}, return the first one as
+     * specified in the constructor. If there is a deferred surface, null will be returned.
+     */
+    public @Nullable Surface getSurface() {
+        return mSurfaces[0];
+    }
+
+    /**
+     * Get the immutable list of surfaces associated with this {@link OutputConfiguration}.
+     *
+     * @return the list of surfaces associated with this {@link OutputConfiguration} in the order
+     * specified in the constructor. If there is a deferred surface in the {@link
+     * OutputConfiguration}, it is returned as null as first element of the list. The list should
+     * not be modified.
+     *
+     * @hide
      */
     @NonNull
-    public Surface getSurface() {
-        return mSurface;
+    public List<Surface> getSurfaces() {
+        return Collections.unmodifiableList(Arrays.asList(mSurfaces));
     }
 
     /**
@@ -423,8 +616,11 @@
         dest.writeInt(mSurfaceType);
         dest.writeInt(mConfiguredSize.getWidth());
         dest.writeInt(mConfiguredSize.getHeight());
-        if (mSurface != null) {
-            mSurface.writeToParcel(dest, flags);
+        dest.writeInt(mSurfaces.length);
+        for (int i = 0; i < mSurfaces.length; i++) {
+            if (mSurfaces[i] != null) {
+                mSurfaces[i].writeToParcel(dest, flags);
+            }
         }
     }
 
@@ -445,20 +641,26 @@
             return true;
         } else if (obj instanceof OutputConfiguration) {
             final OutputConfiguration other = (OutputConfiguration) obj;
-            boolean iSSurfaceEqual = mSurface == other.mSurface &&
-                    mConfiguredGenerationId == other.mConfiguredGenerationId ;
-            if (mIsDeferredConfig) {
-                Log.i(TAG, "deferred config has the same surface");
-                iSSurfaceEqual = true;
+            if (mRotation != other.mRotation ||
+                    !mConfiguredSize.equals(other.mConfiguredSize) ||
+                    mConfiguredFormat != other.mConfiguredFormat ||
+                    mSurfaceGroupId != other.mSurfaceGroupId ||
+                    mSurfaceType != other.mSurfaceType ||
+                    mIsDeferredConfig != other.mIsDeferredConfig ||
+                    mConfiguredFormat != other.mConfiguredFormat ||
+                    mConfiguredDataspace != other.mConfiguredDataspace ||
+                    mSurfaces.length != other.mSurfaces.length ||
+                    mConfiguredGenerationId != other.mConfiguredGenerationId)
+                return false;
+
+            // If deferred, skip the first surface of mSurfaces when comparing.
+            int minIndex = (mIsDeferredConfig ? 1 : 0);
+            for (int i = minIndex;  i < mSurfaces.length; i++) {
+                if (mSurfaces[i] != other.mSurfaces[i])
+                    return false;
             }
-            return mRotation == other.mRotation &&
-                   iSSurfaceEqual&&
-                   mConfiguredSize.equals(other.mConfiguredSize) &&
-                   mConfiguredFormat == other.mConfiguredFormat &&
-                   mConfiguredDataspace == other.mConfiguredDataspace &&
-                   mSurfaceGroupId == other.mSurfaceGroupId &&
-                   mSurfaceType == other.mSurfaceType &&
-                   mIsDeferredConfig == other.mIsDeferredConfig;
+
+            return true;
         }
         return false;
     }
@@ -469,21 +671,22 @@
     @Override
     public int hashCode() {
         // Need ensure that the hashcode remains unchanged after set a deferred surface. Otherwise
-        // The deferred output configuration will be lost in the camera streammap after the deferred
+        // the deferred output configuration will be lost in the camera streammap after the deferred
         // surface is set.
-        if (mIsDeferredConfig) {
-            return HashCodeHelpers.hashCode(
-                    mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
-                    mSurfaceGroupId, mSurfaceType);
-        }
+        int minIndex = (mIsDeferredConfig ? 1 : 0);
+        Surface nonDeferredSurfaces[] = Arrays.copyOfRange(mSurfaces,
+                minIndex, mSurfaces.length);
+        int surfaceHash = HashCodeHelpers.hashCodeGeneric(nonDeferredSurfaces);
 
         return HashCodeHelpers.hashCode(
-            mRotation, mSurface.hashCode(), mConfiguredGenerationId,
-            mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId);
+                mRotation, surfaceHash, mConfiguredGenerationId,
+                mConfiguredSize.hashCode(), mConfiguredFormat,
+                mConfiguredDataspace, mSurfaceGroupId);
     }
 
     private static final String TAG = "OutputConfiguration";
-    private Surface mSurface;
+    private static final int MAX_SURFACES_COUNT = 2;
+    private Surface mSurfaces[];
     private final int mRotation;
     private final int mSurfaceGroupId;
     // Surface source type, this is only used by the deferred surface configuration objects.
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index aea1258..3eb5844 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -19,6 +19,8 @@
 import android.hardware.SensorManager;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.util.IntArray;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 
@@ -147,6 +149,21 @@
     public abstract void setDisplayOffsets(int displayId, int x, int y);
 
     /**
+     * Provide a list of UIDs that are present on the display and are allowed to access it.
+     *
+     * @param displayAccessUIDs Mapping displayId -> int array of UIDs.
+     */
+    public abstract void setDisplayAccessUIDs(SparseArray<IntArray> displayAccessUIDs);
+
+    /**
+     * Check if specified UID's content is present on display and should be granted access to it.
+     *
+     * @param uid UID to be checked.
+     * @param displayId id of the display where presence of the content is checked.
+     * */
+    public abstract boolean isUidPresentOnDisplay(int uid, int displayId);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index c704ef0..0775bda 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -24,8 +24,10 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Build;
+import android.service.NetworkIdentityProto;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.Objects;
 
@@ -110,6 +112,23 @@
         return builder.append("}").toString();
     }
 
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        proto.write(NetworkIdentityProto.TYPE, mType);
+
+        // Not dumping mSubType, subtypes are no longer supported.
+
+        if (mSubscriberId != null) {
+            proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId));
+        }
+        proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
+        proto.write(NetworkIdentityProto.ROAMING, mRoaming);
+        proto.write(NetworkIdentityProto.METERED, mMetered);
+
+        proto.end(start);
+    }
+
     public int getType() {
         return mType;
     }
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index ffbc401..1a128e0 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.SystemApi;
+import android.net.wifi.ScanResult;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -52,6 +53,18 @@
     public final WifiKey wifiKey;
 
     /**
+     * Constructs a new NetworkKey for the given wifi {@link ScanResult}.
+     *
+     * @throws IllegalArgumentException if the given ScanResult is malformed
+     * @hide
+     */
+    public static NetworkKey createFromScanResult(ScanResult result) {
+        return new NetworkKey(
+                new WifiKey(
+                        '"' + result.wifiSsid.toString() + '"', result.BSSID));
+    }
+
+    /**
      * Construct a new {@link NetworkKey} for a Wi-Fi network.
      * @param wifiKey the {@link WifiKey} identifying this Wi-Fi network.
      */
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 7a832d1..57cf1a5 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -36,6 +37,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * Class that manages communication between network subsystems and a network scorer.
@@ -370,25 +372,26 @@
      *
      * @param request a {@link RecommendationRequest} instance containing additional
      *                request details
-     * @param callback a {@link RecommendationCallback} instance that will be invoked when
-     *                 the {@link RecommendationResult} is available
-     * @param handler a {@link Handler} instance representing the thread to run the callback on.
+     * @param handler a {@link Handler} instance representing the thread to complete the future on.
+     *                If null the responding binder thread will be used.
+     * @return a {@link CompletableFuture} instance that will eventually receive the
+     *         {@link RecommendationResult}.
      * @throws SecurityException
      * @hide
      */
-    public void requestRecommendation(
+    public CompletableFuture<RecommendationResult> requestRecommendation(
             final @NonNull RecommendationRequest request,
-            final @NonNull RecommendationCallback callback,
-            final @NonNull Handler handler) {
+            final @Nullable Handler handler) {
         Preconditions.checkNotNull(request, "RecommendationRequest cannot be null.");
-        Preconditions.checkNotNull(callback, "RecommendationCallback cannot be null.");
-        Preconditions.checkNotNull(handler, "Handler cannot be null.");
+
+        final CompletableFuture<RecommendationResult> futureResult =
+                new CompletableFuture<>();
 
         RemoteCallback remoteCallback = new RemoteCallback(new RemoteCallback.OnResultListener() {
             @Override
             public void onResult(Bundle data) {
                 RecommendationResult result = data.getParcelable(EXTRA_RECOMMENDATION_RESULT);
-                callback.onRecommendationAvailable(result);
+                futureResult.complete(result);
             }
         }, handler);
 
@@ -397,18 +400,7 @@
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-    }
 
-    /**
-     * Callers of {@link #requestRecommendation(RecommendationRequest, RecommendationCallback, Handler)}
-     * must pass in an implementation of this class.
-     * @hide
-     */
-    public abstract static class RecommendationCallback {
-        /**
-         * Invoked when a {@link RecommendationResult} is available.
-         * @param result a {@link RecommendationResult} instance.
-         */
-        public abstract void onRecommendationAvailable(RecommendationResult result);
+        return futureResult;
     }
 }
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 23d5af5..9e4dd87 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -226,16 +226,6 @@
         return false;
     }
 
-    /** Determine whether the application with the given UID is the enabled scorer. */
-    @Deprecated // Use NetworkScoreManager.isCallerActiveScorer()
-    public boolean isCallerActiveScorer(int callingUid) {
-        NetworkScorerAppData defaultApp = getActiveScorer();
-        if (defaultApp == null) {
-            return false;
-        }
-        return callingUid == defaultApp.packageUid;
-    }
-
     private boolean isNetworkRecommendationsDisabled() {
         final ContentResolver cr = mContext.getContentResolver();
         // A value of 1 indicates enabled.
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 4a4accb..5f521de 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -31,7 +31,10 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.service.NetworkStatsHistoryBucketProto;
+import android.service.NetworkStatsHistoryProto;
 import android.util.MathUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -628,6 +631,33 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
+
+        for (int i = 0; i < bucketCount; i++) {
+            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
+
+            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
+
+            proto.end(startBucket);
+        }
+
+        proto.end(start);
+    }
+
+    private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
+        if (array != null) {
+            proto.write(tag, array[index]);
+        }
+    }
+
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
index d013f64..b89a245 100644
--- a/core/java/android/net/RecommendationRequest.java
+++ b/core/java/android/net/RecommendationRequest.java
@@ -34,8 +34,11 @@
 @SystemApi
 public final class RecommendationRequest implements Parcelable {
     private final ScanResult[] mScanResults;
-    private final WifiConfiguration mCurrentSelectedConfig;
-    private final NetworkCapabilities mRequiredCapabilities;
+    private final WifiConfiguration mDefaultConfig;
+    private WifiConfiguration mConnectedConfig;
+    private WifiConfiguration[] mConnectableConfigs;
+    private final int mLastSelectedNetworkId;
+    private final long mLastSelectedNetworkTimestamp;
 
     /**
      * Builder class for constructing {@link RecommendationRequest} instances.
@@ -44,26 +47,65 @@
     @SystemApi
     public static final class Builder {
         private ScanResult[] mScanResults;
-        private WifiConfiguration mCurrentConfig;
-        private NetworkCapabilities mNetworkCapabilities;
+        private WifiConfiguration mDefaultConfig;
+        private WifiConfiguration mConnectedConfig;
+        private WifiConfiguration[] mConnectableConfigs;
+        private int mLastSelectedNetworkId;
+        private long mLastSelectedTimestamp;
 
         public Builder setScanResults(ScanResult[] scanResults) {
             mScanResults = scanResults;
             return this;
         }
 
-        public Builder setCurrentRecommendedWifiConfig(WifiConfiguration config) {
-            this.mCurrentConfig = config;
+        /**
+         * @param config the {@link WifiConfiguration} to return if no recommendation is available.
+         * @return this
+         */
+        public Builder setDefaultWifiConfig(WifiConfiguration config) {
+            this.mDefaultConfig = config;
             return this;
         }
 
-        public Builder setNetworkCapabilities(NetworkCapabilities capabilities) {
-            mNetworkCapabilities = capabilities;
+        /**
+         * @param config the {@link WifiConfiguration} of the connected network at the time the
+         *               this request was made.
+         * @return this
+         */
+        public Builder setConnectedWifiConfig(WifiConfiguration config) {
+            this.mConnectedConfig = config;
             return this;
         }
 
+        /**
+         * @param connectableConfigs the set of saved {@link WifiConfiguration}s that can be
+         *                           connected to based on the current set of {@link ScanResult}s.
+         * @return this
+         */
+        public Builder setConnectableConfigs(WifiConfiguration[] connectableConfigs) {
+            this.mConnectableConfigs = connectableConfigs;
+            return this;
+        }
+
+        /**
+         * @param networkId The {@link WifiConfiguration#networkId} of the last user selected
+         *                  network.
+         * @param timestamp The {@link android.os.SystemClock#elapsedRealtime()} when the user
+         *                  selected {@code networkId}.
+         * @return this
+         */
+        public Builder setLastSelectedNetwork(int networkId, long timestamp) {
+            this.mLastSelectedNetworkId = networkId;
+            this.mLastSelectedTimestamp = timestamp;
+            return this;
+        }
+
+        /**
+         * @return a new {@link RecommendationRequest} instance
+         */
         public RecommendationRequest build() {
-            return new RecommendationRequest(mScanResults, mCurrentConfig, mNetworkCapabilities);
+            return new RecommendationRequest(mScanResults, mDefaultConfig, mConnectedConfig,
+                    mConnectableConfigs, mLastSelectedNetworkId, mLastSelectedTimestamp);
         }
     }
 
@@ -79,45 +121,103 @@
     }
 
     /**
-     * @return The best recommendation at the time this {@code RecommendationRequest} instance
-     *         was created. This may be null which indicates that no recommendation is available.
+     * @return the {@link WifiConfiguration} to return if no recommendation is available.
      */
-    public WifiConfiguration getCurrentSelectedConfig() {
-        return mCurrentSelectedConfig;
+    public WifiConfiguration getDefaultWifiConfig() {
+        return mDefaultConfig;
     }
 
     /**
-     *
-     * @return The set of {@link NetworkCapabilities} the recommendation must be constrained to.
-     *         This may be {@code null} which indicates that there are no constraints on the
-     *         capabilities of the recommended network.
+     * @return the {@link WifiConfiguration} of the connected network at the time the this request
+     *         was made.
      */
-    public NetworkCapabilities getRequiredCapabilities() {
-        return mRequiredCapabilities;
+    public WifiConfiguration getConnectedConfig() {
+        return mConnectedConfig;
+    }
+
+    /**
+     * @return the set of saved {@link WifiConfiguration}s that can be connected to based on the
+     *         current set of {@link ScanResult}s.
+     */
+    public WifiConfiguration[] getConnectableConfigs() {
+        return mConnectableConfigs;
+    }
+
+    /**
+     * @param connectedConfig the {@link WifiConfiguration} of the connected network at the time
+     *                        the this request was made.
+     */
+    public void setConnectedConfig(WifiConfiguration connectedConfig) {
+        mConnectedConfig = connectedConfig;
+    }
+
+    /**
+     * @param connectableConfigs the set of saved {@link WifiConfiguration}s that can be connected
+     *                           to based on the current set of {@link ScanResult}s.
+     */
+    public void setConnectableConfigs(WifiConfiguration[] connectableConfigs) {
+        mConnectableConfigs = connectableConfigs;
+    }
+
+    /**
+     * @return The {@link WifiConfiguration#networkId} of the last user selected network.
+     *         {@code 0} if not set.
+     */
+    public int getLastSelectedNetworkId() {
+        return mLastSelectedNetworkId;
+    }
+
+    /**
+     * @return The {@link android.os.SystemClock#elapsedRealtime()} when the user selected
+     *         {@link #getLastSelectedNetworkId()}. {@code 0} if not set.
+     */
+    public long getLastSelectedNetworkTimestamp() {
+        return mLastSelectedNetworkTimestamp;
     }
 
     @VisibleForTesting
     RecommendationRequest(ScanResult[] scanResults,
-            WifiConfiguration currentSelectedConfig,
-            NetworkCapabilities requiredCapabilities) {
+            WifiConfiguration defaultWifiConfig,
+            WifiConfiguration connectedWifiConfig,
+            WifiConfiguration[] connectableConfigs,
+            int lastSelectedNetworkId,
+            long lastSelectedNetworkTimestamp) {
         mScanResults = scanResults;
-        mCurrentSelectedConfig = currentSelectedConfig;
-        mRequiredCapabilities = requiredCapabilities;
+        mDefaultConfig = defaultWifiConfig;
+        mConnectedConfig = connectedWifiConfig;
+        mConnectableConfigs = connectableConfigs;
+        mLastSelectedNetworkId = lastSelectedNetworkId;
+        mLastSelectedNetworkTimestamp = lastSelectedNetworkTimestamp;
     }
 
     protected RecommendationRequest(Parcel in) {
         final int resultCount = in.readInt();
         if (resultCount > 0) {
             mScanResults = new ScanResult[resultCount];
+            final ClassLoader classLoader = ScanResult.class.getClassLoader();
             for (int i = 0; i < resultCount; i++) {
-                mScanResults[i] = in.readParcelable(ScanResult.class.getClassLoader());
+                mScanResults[i] = in.readParcelable(classLoader);
             }
         } else {
             mScanResults = null;
         }
 
-        mCurrentSelectedConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
-        mRequiredCapabilities = in.readParcelable(NetworkCapabilities.class.getClassLoader());
+        mDefaultConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
+        mConnectedConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
+
+        final int configCount = in.readInt();
+        if (configCount > 0) {
+            mConnectableConfigs = new WifiConfiguration[configCount];
+            final ClassLoader classLoader = WifiConfiguration.class.getClassLoader();
+            for (int i = 0; i < configCount; i++) {
+                mConnectableConfigs[i] = in.readParcelable(classLoader);
+            }
+        } else {
+            mConnectableConfigs = null;
+        }
+
+        mLastSelectedNetworkId = in.readInt();
+        mLastSelectedNetworkTimestamp = in.readLong();
     }
 
     @Override
@@ -135,8 +235,21 @@
         } else {
             dest.writeInt(0);
         }
-        dest.writeParcelable(mCurrentSelectedConfig, flags);
-        dest.writeParcelable(mRequiredCapabilities, flags);
+
+        dest.writeParcelable(mDefaultConfig, flags);
+        dest.writeParcelable(mConnectedConfig, flags);
+
+        if (mConnectableConfigs != null) {
+            dest.writeInt(mConnectableConfigs.length);
+            for (int i = 0; i < mConnectableConfigs.length; i++) {
+                dest.writeParcelable(mConnectableConfigs[i], flags);
+            }
+        } else {
+            dest.writeInt(0);
+        }
+
+        dest.writeInt(mLastSelectedNetworkId);
+        dest.writeLong(mLastSelectedNetworkTimestamp);
     }
 
     public static final Creator<RecommendationRequest> CREATOR =
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index cea56b5..ffc735c 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -96,6 +96,7 @@
 
     public boolean requestTime(InetAddress address, int port, int timeout) {
         DatagramSocket socket = null;
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NTP);
         try {
             socket = new DatagramSocket();
             socket.setSoTimeout(timeout);
@@ -161,6 +162,7 @@
             if (socket != null) {
                 socket.close();
             }
+            TrafficStats.setThreadStatsTag(oldTag);
         }
 
         return true;
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index e7436be..fc66395 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -168,6 +168,24 @@
 
     /**
      * Set active tag to use when accounting {@link Socket} traffic originating
+     * from the current thread. Only one active tag per thread is supported.
+     * <p>
+     * Changes only take effect during subsequent calls to
+     * {@link #tagSocket(Socket)}.
+     * <p>
+     * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and
+     * used internally by system services like {@link DownloadManager} when
+     * performing traffic on behalf of an application.
+     *
+     * @return the current tag for the calling thread, which can be used to
+     *         restore any existing values after a nested operation is finished
+     */
+    public static int getAndSetThreadStatsTag(int tag) {
+        return NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
+    }
+
+    /**
+     * Set active tag to use when accounting {@link Socket} traffic originating
      * from the current thread. The tag used internally is well-defined to
      * distinguish all backup-related traffic.
      *
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index daf8b2d..80ecf97 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -887,6 +887,21 @@
             "eng".equals(getString("ro.build.type"));
 
     /**
+     * Whether this build is running inside a container.
+     *
+     * We should try to avoid checking this flag if possible to minimize
+     * unnecessarily diverging from non-container Android behavior.
+     * Checking this flag is acceptable when low-level resources being
+     * different, e.g. the availability of certain capabilities, access to
+     * system resources being restricted, and the fact that the host OS might
+     * handle some features for us.
+     * For higher-level behavior differences, other checks should be preferred.
+     * @hide
+     */
+    public static final boolean IS_CONTAINER =
+            SystemProperties.getBoolean("ro.boot.container", false);
+
+    /**
      * Specifies whether the permissions needed by a legacy app should be
      * reviewed before any of its components can run. A legacy app is one
      * with targetSdkVersion < 23, i.e apps using the old permission model.
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 73c9462..7c015de 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -38,7 +38,6 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
@@ -334,12 +333,7 @@
      * @throws IOException
      */
     public static void stringToFile(String filename, String string) throws IOException {
-        FileWriter out = new FileWriter(filename);
-        try {
-            out.write(string);
-        } finally {
-            out.close();
-        }
+        bytesToFile(filename, string.getBytes(StandardCharsets.UTF_8));
     }
 
     /**
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 4b130ed1..20de370 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.opengl.EGL14;
 import android.os.SystemProperties;
 import android.util.Log;
 
@@ -34,6 +35,23 @@
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
 
     public static void setupGraphicsEnvironment(Context context) {
+        chooseDriver(context);
+
+        // Now that we've figured out which driver to use for this process, load and initialize it.
+        // This can take multiple frame periods, and it would otherwise happen as part of the first
+        // frame, increasing first-frame latency. Starting it here, as a low-priority background
+        // thread, means that it's usually done long before we start drawing the first frame,
+        // without significantly disrupting other activity launch work.
+        Thread eglInitThread = new Thread(
+                () -> {
+                    Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+                    EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+                },
+                "EGL Init");
+        eglInitThread.start();
+    }
+
+    private static void chooseDriver(Context context) {
         String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
         if (driverPackageName == null || driverPackageName.isEmpty()) {
             return;
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 1ee83ae..c5ceecd 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -25,5 +25,5 @@
     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
     boolean setupBcb(in String command);
     boolean clearBcb();
-    void rebootRecoveryWithCommand(in String command, in boolean update);
+    void rebootRecoveryWithCommand(in String command);
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 9513854..1c2588a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -19,6 +19,7 @@
 
 import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.os.UserManager;
 import android.content.pm.UserInfo;
 import android.content.IntentSender;
 import android.content.RestrictionEntry;
@@ -61,6 +62,7 @@
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
     int getUserRestrictionSource(String restrictionKey, int userHandle);
+    List<UserManager.EnforcingUser> getUserRestrictionSources(String restrictionKey, int userHandle);
     Bundle getUserRestrictions(int userHandle);
     boolean hasBaseUserRestriction(String restrictionKey, int userHandle);
     boolean hasUserRestriction(in String restrictionKey, int userHandle);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e15f086..d6d5cb6 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -27,6 +27,8 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
+import libcore.util.SneakyThrow;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
@@ -250,6 +252,7 @@
     private static final int EX_NETWORK_MAIN_THREAD = -6;
     private static final int EX_UNSUPPORTED_OPERATION = -7;
     private static final int EX_SERVICE_SPECIFIC = -8;
+    private static final int EX_PARCELABLE = -9;
     private static final int EX_HAS_REPLY_HEADER = -128;  // special; see below
     // EX_TRANSACTION_FAILED is used exclusively in native code.
     // see libbinder's binder/Status.h
@@ -1597,7 +1600,12 @@
      */
     public final void writeException(Exception e) {
         int code = 0;
-        if (e instanceof SecurityException) {
+        if (e instanceof Parcelable
+                && (e.getClass().getClassLoader() == Parcelable.class.getClassLoader())) {
+            // We only send Parcelable exceptions that are in the
+            // BootClassLoader to ensure that the receiver can unpack them
+            code = EX_PARCELABLE;
+        } else if (e instanceof SecurityException) {
             code = EX_SECURITY;
         } else if (e instanceof BadParcelableException) {
             code = EX_BAD_PARCELABLE;
@@ -1623,8 +1631,20 @@
             throw new RuntimeException(e);
         }
         writeString(e.getMessage());
-        if (e instanceof ServiceSpecificException) {
-            writeInt(((ServiceSpecificException)e).errorCode);
+        switch (code) {
+            case EX_SERVICE_SPECIFIC:
+                writeInt(((ServiceSpecificException) e).errorCode);
+                break;
+            case EX_PARCELABLE:
+                // Write parceled exception prefixed by length
+                final int sizePosition = dataPosition();
+                writeInt(0);
+                writeParcelable((Parcelable) e, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+                final int payloadPosition = dataPosition();
+                setDataPosition(sizePosition);
+                writeInt(payloadPosition - sizePosition);
+                setDataPosition(payloadPosition);
+                break;
         }
     }
 
@@ -1722,6 +1742,13 @@
      */
     public final void readException(int code, String msg) {
         switch (code) {
+            case EX_PARCELABLE:
+                if (readInt() > 0) {
+                    SneakyThrow.sneakyThrow(
+                            (Exception) readParcelable(Parcelable.class.getClassLoader()));
+                } else {
+                    throw new RuntimeException(msg + " [missing Parcelable]");
+                }
             case EX_SECURITY:
                 throw new SecurityException(msg);
             case EX_BAD_PARCELABLE:
diff --git a/core/java/android/os/ParcelableException.java b/core/java/android/os/ParcelableException.java
new file mode 100644
index 0000000..d84d629
--- /dev/null
+++ b/core/java/android/os/ParcelableException.java
@@ -0,0 +1,88 @@
+/*
+ * 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.os;
+
+import java.io.IOException;
+
+/**
+ * Wrapper class that offers to transport typical {@link Throwable} across a
+ * {@link Binder} call. This class is typically used to transport exceptions
+ * that cannot be modified to add {@link Parcelable} behavior, such as
+ * {@link IOException}.
+ * <ul>
+ * <li>The wrapped throwable must be defined as system class (that is, it must
+ * be in the same {@link ClassLoader} as {@link Parcelable}).
+ * <li>The wrapped throwable must support the
+ * {@link Throwable#Throwable(String)} constructor.
+ * <li>The receiver side must catch any thrown {@link ParcelableException} and
+ * call {@link #maybeRethrow(Class)} for all expected exception types.
+ * </ul>
+ *
+ * @hide
+ */
+public final class ParcelableException extends RuntimeException implements Parcelable {
+    public ParcelableException(Throwable t) {
+        super(t);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends Throwable> void maybeRethrow(Class<T> clazz) throws T {
+        if (clazz.isAssignableFrom(getCause().getClass())) {
+            throw (T) getCause();
+        }
+    }
+
+    /** {@hide} */
+    public static Throwable readFromParcel(Parcel in) {
+        final String name = in.readString();
+        final String msg = in.readString();
+        try {
+            final Class<?> clazz = Class.forName(name, true, Parcelable.class.getClassLoader());
+            return (Throwable) clazz.getConstructor(String.class).newInstance(msg);
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(name + ": " + msg);
+        }
+    }
+
+    /** {@hide} */
+    public static void writeToParcel(Parcel out, Throwable t) {
+        out.writeString(t.getClass().getName());
+        out.writeString(t.getMessage());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        writeToParcel(dest, getCause());
+    }
+
+    public static final Creator<ParcelableException> CREATOR = new Creator<ParcelableException>() {
+        @Override
+        public ParcelableException createFromParcel(Parcel source) {
+            return new ParcelableException(readFromParcel(source));
+        }
+
+        @Override
+        public ParcelableException[] newArray(int size) {
+            return new ParcelableException[size];
+        }
+    };
+}
diff --git a/core/java/android/os/IProxyFileDescriptorCallback.java b/core/java/android/os/ProxyFileDescriptorCallback.java
similarity index 69%
rename from core/java/android/os/IProxyFileDescriptorCallback.java
rename to core/java/android/os/ProxyFileDescriptorCallback.java
index e41e194..2e9f8d9 100644
--- a/core/java/android/os/IProxyFileDescriptorCallback.java
+++ b/core/java/android/os/ProxyFileDescriptorCallback.java
@@ -17,18 +17,20 @@
 package android.os;
 
 import android.system.ErrnoException;
+import android.system.OsConstants;
 
 /**
  * Callback that handles file system requests from ProxyFileDescriptor.
- * @hide
  */
-public interface IProxyFileDescriptorCallback {
+public abstract class ProxyFileDescriptorCallback {
     /**
      * Returns size of bytes provided by the file descriptor.
      * @return Size of bytes
      * @throws ErrnoException
      */
-    long onGetSize() throws ErrnoException;
+    public long onGetSize() throws ErrnoException {
+        throw new ErrnoException("onGetSize", OsConstants.EBADF);
+    }
 
     /**
      * Provides bytes read from file descriptor.
@@ -39,7 +41,9 @@
      * @return Size of bytes returned by the function.
      * @throws ErrnoException
      */
-    int onRead(long offset, int size, byte[] data) throws ErrnoException;
+    public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+        throw new ErrnoException("onRead", OsConstants.EBADF);
+    }
 
     /**
      * Handles bytes written to file descriptor.
@@ -49,11 +53,20 @@
      * @return Size of bytes processed by the function.
      * @throws ErrnoException
      */
-    int onWrite(long offset, int size, byte[] data) throws ErrnoException;
+    public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+        throw new ErrnoException("onWrite", OsConstants.EBADF);
+    }
 
     /**
      * Processes fsync request.
      * @throws ErrnoException
      */
-    void onFsync() throws ErrnoException;
+    public void onFsync() throws ErrnoException {
+        throw new ErrnoException("onFsync", OsConstants.EINVAL);
+    }
+
+    /**
+     * Invoked after the file is closed.
+     */
+    abstract public void onRelease();
 }
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 7f9ea438..a8822c5 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -491,10 +491,15 @@
                 command += securityArg;
             }
 
-            // RECOVERY_SERVICE writes to BCB (bootloader control block) and triggers the reboot.
             RecoverySystem rs = (RecoverySystem) context.getSystemService(
                     Context.RECOVERY_SERVICE);
-            rs.rebootRecoveryWithCommand(command, true /* update */);
+            if (!rs.setupBcb(command)) {
+                throw new IOException("Setup BCB failed");
+            }
+
+            // Having set up the BCB (bootloader control block), go ahead and reboot
+            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+            pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE);
 
             throw new IOException("Reboot failed (no permissions?)");
         }
@@ -645,6 +650,18 @@
         bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
     }
 
+    /** {@hide} */
+    public static void rebootPromptAndWipeUserData(Context context, String reason)
+            throws IOException {
+        String reasonArg = null;
+        if (!TextUtils.isEmpty(reason)) {
+            reasonArg = "--reason=" + sanitizeArg(reason);
+        }
+
+        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        bootCommand(context, null, "--prompt_and_wipe_data", reasonArg, localeArg);
+    }
+
     /**
      * Reboot into the recovery system to wipe the /cache partition.
      * @throws IOException if something goes wrong.
@@ -708,7 +725,7 @@
         // Write the command into BCB (bootloader control block) and boot from
         // there. Will not return unless failed.
         RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
-        rs.rebootRecoveryWithCommand(command.toString(), false);
+        rs.rebootRecoveryWithCommand(command.toString());
 
         throw new IOException("Reboot failed (no permissions?)");
     }
@@ -908,9 +925,9 @@
      * Talks to RecoverySystemService via Binder to set up the BCB command and
      * reboot into recovery accordingly.
      */
-    private void rebootRecoveryWithCommand(String command, boolean update) {
+    private void rebootRecoveryWithCommand(String command) {
         try {
-            mService.rebootRecoveryWithCommand(command, update);
+            mService.rebootRecoveryWithCommand(command);
         } catch (RemoteException ignored) {
         }
     }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 0da4bd1..ae981b7 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.net.TrafficStats;
 import android.net.Uri;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -245,11 +246,17 @@
      */
     private static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8;  // for VmPolicy
 
+    /**
+     * @hide
+     */
+    private static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24;  // for VmPolicy
+
     private static final int ALL_VM_DETECT_BITS =
             DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
             DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
             DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE |
-            DETECT_VM_CLEARTEXT_NETWORK | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
+            DETECT_VM_CLEARTEXT_NETWORK | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION |
+            DETECT_VM_UNTAGGED_SOCKET;
 
     // Byte 3: Penalty
 
@@ -300,6 +307,8 @@
      */
     public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
 
+    // CAUTION: we started stealing the top bits of Byte 4 for VM above
+
     /**
      * Mask of all the penalty bits valid for thread policies.
      */
@@ -715,7 +724,8 @@
             public Builder detectAll() {
                 int flags = DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS
                         | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS
-                        | DETECT_VM_FILE_URI_EXPOSURE | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
+                        | DETECT_VM_FILE_URI_EXPOSURE | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION
+                        | DETECT_VM_UNTAGGED_SOCKET;
 
                 // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have facility
                 // for apps to mark sockets that should be ignored
@@ -820,6 +830,22 @@
             }
 
             /**
+             * Detect any sockets in the calling app which have not been tagged
+             * using {@link TrafficStats}. Tagging sockets can help you
+             * investigate network usage inside your app, such as a narrowing
+             * down heavy usage to a specific library or component.
+             * <p>
+             * This currently does not detect sockets created in native code.
+             *
+             * @see TrafficStats#setThreadStatsTag(int)
+             * @see TrafficStats#tagSocket(java.net.Socket)
+             * @see TrafficStats#tagDatagramSocket(java.net.DatagramSocket)
+             */
+            public Builder detectUntaggedSockets() {
+                return enable(DETECT_VM_UNTAGGED_SOCKET);
+            }
+
+            /**
              * Crashes the whole process on violation. This penalty runs at the
              * end of all enabled penalties so you'll still get your logging or
              * other violations before the process dies.
@@ -1152,6 +1178,11 @@
             if (IS_ENG_BUILD) {
                 policyBuilder.penaltyLog();
             }
+            // All core system components need to tag their sockets to aid
+            // system health investigations
+            if (android.os.Process.myUid() < android.os.Process.FIRST_APPLICATION_UID) {
+                policyBuilder.detectUntaggedSockets();
+            }
             setVmPolicy(policyBuilder.build());
             setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
         }
@@ -1832,6 +1863,13 @@
     /**
      * @hide
      */
+    public static boolean vmUntaggedSocketEnabled() {
+        return (sVmPolicyMask & DETECT_VM_UNTAGGED_SOCKET) != 0;
+    }
+
+    /**
+     * @hide
+     */
     public static void onSqliteObjectLeaked(String message, Throwable originStack) {
         onVmPolicyViolation(message, originStack);
     }
@@ -1911,6 +1949,14 @@
                 forceDeath);
     }
 
+    /**
+     * @hide
+     */
+    public static void onUntaggedSocket() {
+        onVmPolicyViolation(null, new Throwable("Untagged socket detected; use"
+                + " TrafficStats.setThreadSocketTag() to track all network usage"));
+    }
+
     // Map from VM violation fingerprint to uptime millis.
     private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
 
diff --git a/core/java/android/os/UserManager.aidl b/core/java/android/os/UserManager.aidl
new file mode 100644
index 0000000..2611b0f
--- /dev/null
+++ b/core/java/android/os/UserManager.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 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.os;
+
+parcelable UserManager.EnforcingUser;
\ No newline at end of file
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3478eaa..efacb20 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1187,7 +1187,9 @@
      * @return The source of user restriction. Any combination of {@link #RESTRICTION_NOT_SET},
      *         {@link #RESTRICTION_SOURCE_SYSTEM}, {@link #RESTRICTION_SOURCE_DEVICE_OWNER}
      *         and {@link #RESTRICTION_SOURCE_PROFILE_OWNER}
+     * @deprecated use {@link #getUserRestrictionSources(String, int)} instead.
      */
+    @Deprecated
     @SystemApi
     @UserRestrictionSource
     public int getUserRestrictionSource(String restrictionKey, UserHandle userHandle) {
@@ -1199,6 +1201,25 @@
     }
 
     /**
+     * @hide
+     *
+     * Returns a list of users who set a user restriction on a given user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param restrictionKey the string key representing the restriction
+     * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+     * @return a list of user ids enforcing this restriction.
+     */
+    @SystemApi
+    public List<EnforcingUser> getUserRestrictionSources(
+            String restrictionKey, UserHandle userHandle) {
+        try {
+            return mService.getUserRestrictionSources(restrictionKey, userHandle.getIdentifier());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the user-wide restrictions imposed on this user.
      * @return a Bundle containing all the restrictions.
      */
@@ -2310,8 +2331,8 @@
      * @hide
      * Checks if any uninitialized user has the specific seed account name and type.
      *
-     * @param mAccountName The account name to check for
-     * @param mAccountType The account type of the account to check for
+     * @param accountName The account name to check for
+     * @param accountType The account type of the account to check for
      * @return whether the seed account was found
      */
     public boolean someUserHasSeedAccount(String accountName, String accountType) {
@@ -2321,4 +2342,73 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * @hide
+     * User that enforces a restriction.
+     *
+     * @see #getUserRestrictionSources(String, UserHandle)
+     */
+    @SystemApi
+    public static final class EnforcingUser implements Parcelable {
+        private final @UserIdInt int userId;
+        private final @UserRestrictionSource int userRestrictionSource;
+
+        /**
+         * @hide
+         */
+        public EnforcingUser(
+                @UserIdInt int userId, @UserRestrictionSource int userRestrictionSource) {
+            this.userId = userId;
+            this.userRestrictionSource = userRestrictionSource;
+        }
+
+        private EnforcingUser(Parcel in) {
+            userId = in.readInt();
+            userRestrictionSource = in.readInt();
+        }
+
+        public static final Creator<EnforcingUser> CREATOR = new Creator<EnforcingUser>() {
+            @Override
+            public EnforcingUser createFromParcel(Parcel in) {
+                return new EnforcingUser(in);
+            }
+
+            @Override
+            public EnforcingUser[] newArray(int size) {
+                return new EnforcingUser[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(userId);
+            dest.writeInt(userRestrictionSource);
+        }
+
+        /**
+         * Returns an id of the enforcing user.
+         *
+         * <p> Will be UserHandle.USER_NULL when restriction is set by the system.
+         */
+        public UserHandle getUserHandle() {
+            return UserHandle.of(userId);
+        }
+
+        /**
+         * Returns the status of the enforcing user.
+         *
+         * <p> One of {@link #RESTRICTION_SOURCE_SYSTEM},
+         * {@link #RESTRICTION_SOURCE_DEVICE_OWNER} and
+         * {@link #RESTRICTION_SOURCE_PROFILE_OWNER}
+         */
+        public @UserRestrictionSource int getUserRestrictionSource() {
+            return userRestrictionSource;
+        }
+    }
 }
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 466a7e3..97da588 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -15,7 +15,6 @@
  */
 package android.os;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
@@ -24,6 +23,10 @@
  * @hide Only for use within the system server.
  */
 public abstract class UserManagerInternal {
+    public static final int CAMERA_NOT_DISABLED = 0;
+    public static final int CAMERA_DISABLED_LOCALLY = 1;
+    public static final int CAMERA_DISABLED_GLOBALLY = 2;
+
     public interface UserRestrictionsListener {
         /**
          * Called when a user restriction changes.
@@ -36,18 +39,19 @@
     }
 
     /**
-     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
-     * to set per-user as well as global user restrictions.
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
+     * restrictions enforced by the user.
      *
      * @param userId target user id for the local restrictions.
-     * @param localRestrictions per-user restrictions.
-     *     Caller must not change it once passed to this method.
-     * @param globalRestrictions global restrictions set by DO.  Must be null when PO changed user
-     *     restrictions, in which case global restrictions won't change.
-     *     Caller must not change it once passed to this method.
+     * @param restrictions a bundle of user restrictions.
+     * @param isDeviceOwner whether {@code userId} corresponds to device owner user id.
+     * @param cameraRestrictionScope is camera disabled and if so what is the scope of restriction.
+     *        Should be one of {@link #CAMERA_NOT_DISABLED}, {@link #CAMERA_DISABLED_LOCALLY} or
+     *                               {@link #CAMERA_DISABLED_GLOBALLY}
      */
-    public abstract void setDevicePolicyUserRestrictions(int userId,
-            @NonNull Bundle localRestrictions, @Nullable Bundle globalRestrictions);
+    public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
+            boolean isDeviceOwner, int cameraRestrictionScope);
+
     /**
      * Returns the "base" user restrictions.
      *
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 27c0526..35a266b 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -25,6 +25,7 @@
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import com.android.internal.os.AppFuseMount;
 
 /**
  * WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -285,8 +286,11 @@
     void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
     void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
     boolean isConvertibleToFBE() = 68;
-    ParcelFileDescriptor mountAppFuse(in String name) = 69;
     void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
     void fixateNewestUserKeyAuth(int userId) = 71;
     void fstrim(int flags) = 72;
+    AppFuseMount mountProxyFileDescriptorBridge() = 73;
+    ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
+    long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
+    long getCacheSizeBytes(String volumeUuid, int uid) = 76;
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 03fd8d3..626d6f4 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -24,6 +24,7 @@
 import android.app.ActivityThread;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -33,18 +34,26 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.AppFuseMount;
+import com.android.internal.os.FuseAppLoop;
 import com.android.internal.os.RoSystemProperties;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
@@ -56,12 +65,14 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -1314,14 +1325,304 @@
     }
 
     /** {@hide} */
-    public ParcelFileDescriptor mountAppFuse(String name) {
+    @VisibleForTesting
+    public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
+            int mode, ProxyFileDescriptorCallback callback, ThreadFactory factory)
+                    throws IOException {
+        // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
+        // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
+        // the bridge by calling mountProxyFileDescriptorBridge.
+        int retry = 3;
+        while (retry-- > 0) {
+            try {
+                synchronized (mFuseAppLoopLock) {
+                    if (mFuseAppLoop == null) {
+                        final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
+                        if (mount == null) {
+                            Log.e(TAG, "Failed to open proxy file bridge.");
+                            throw new IOException("Failed to open proxy file bridge.");
+                        }
+                        mFuseAppLoop = FuseAppLoop.open(mount.mountPointId, mount.fd, factory);
+                    }
+
+                    try {
+                        final int fileId = mFuseAppLoop.registerCallback(callback);
+                        final ParcelFileDescriptor pfd =
+                                mStorageManager.openProxyFileDescriptor(
+                                        mFuseAppLoop.getMountPointId(), fileId, mode);
+                        if (pfd != null) {
+                            return pfd;
+                        }
+                        // Probably the bridge is being unmounted but mFuseAppLoop has not been
+                        // noticed it yet.
+                        mFuseAppLoop.unregisterCallback(fileId);
+                    } catch (FuseAppLoop.UnmountedException error) {
+                        Log.d(TAG, "mFuseAppLoop has been already unmounted.");
+                        mFuseAppLoop = null;
+                        continue;
+                    }
+                }
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    break;
+                }
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
+        throw new IOException("Failed to mount bridge.");
+    }
+
+    /**
+     * Opens seekable ParcelFileDescriptor that routes file operation requests to
+     * ProxyFileDescriptorCallback.
+     *
+     * @param mode The desired access mode, must be one of
+     *     {@link ParcelFileDescriptor#MODE_READ_ONLY},
+     *     {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
+     *     {@link ParcelFileDescriptor#MODE_READ_WRITE}
+     * @param callback Callback to process file operation requests issued on returned file
+     *     descriptor. The callback is invoked on a thread managed by the framework.
+     * @return Seekable ParcelFileDescriptor.
+     * @throws IOException
+     */
+    public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
+            int mode, ProxyFileDescriptorCallback callback)
+                    throws IOException {
+        return openProxyFileDescriptor(mode, callback, null);
+    }
+
+    /** {@hide} */
+    @VisibleForTesting
+    public int getProxyFileDescriptorMountPointId() {
+        synchronized (mFuseAppLoopLock) {
+            return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
+        }
+    }
+
+    /**
+     * Return quota size in bytes for cached data belonging to the calling app.
+     * <p>
+     * If your app goes above this quota, your cached files will be some of the
+     * first to be deleted when additional disk space is needed. Conversely, if
+     * your app stays under this quota, your cached files will be some of the
+     * last to be deleted when additional disk space is needed.
+     * <p>
+     * This quota may change over time depending on how frequently the user
+     * interacts with your app, and depending on how much disk space is used.
+     * <p>
+     * Cached data tracked by this method always includes
+     * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
+     * it also includes {@link Context#getExternalCacheDir()} if the primary
+     * shared/external storage is hosted on the same storage device as your
+     * private data.
+     * <p class="note">
+     * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+     * then cached data for all packages in your shared UID is tracked together
+     * as a single unit.
+     * </p>
+     *
+     * @see #getCacheQuotaBytes()
+     * @see #getCacheSizeBytes()
+     * @see #getExternalCacheQuotaBytes()
+     * @see #getExternalCacheSizeBytes()
+     */
+    public long getCacheQuotaBytes() {
         try {
-            return mStorageManager.mountAppFuse(name);
+            final ApplicationInfo app = mContext.getApplicationInfo();
+            return mStorageManager.getCacheQuotaBytes(app.volumeUuid, app.uid);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    /**
+     * Return total size in bytes of cached data belonging to the calling app.
+     * <p>
+     * Cached data tracked by this method always includes
+     * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
+     * it also includes {@link Context#getExternalCacheDir()} if the primary
+     * shared/external storage is hosted on the same storage device as your
+     * private data.
+     * <p class="note">
+     * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+     * then cached data for all packages in your shared UID is tracked together
+     * as a single unit.
+     * </p>
+     *
+     * @see #getCacheQuotaBytes()
+     * @see #getCacheSizeBytes()
+     * @see #getExternalCacheQuotaBytes()
+     * @see #getExternalCacheSizeBytes()
+     */
+    public long getCacheSizeBytes() {
+        try {
+            final ApplicationInfo app = mContext.getApplicationInfo();
+            return mStorageManager.getCacheSizeBytes(app.volumeUuid, app.uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return quota size in bytes for cached data on primary shared/external
+     * storage belonging to the calling app.
+     * <p>
+     * If primary shared/external storage is hosted on the same storage device
+     * as your private data, this method will return -1, since all data stored
+     * under {@link Context#getExternalCacheDir()} will be counted under
+     * {@link #getCacheQuotaBytes()}.
+     * <p class="note">
+     * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+     * then cached data for all packages in your shared UID is tracked together
+     * as a single unit.
+     * </p>
+     */
+    public long getExternalCacheQuotaBytes() {
+        final ApplicationInfo app = mContext.getApplicationInfo();
+        final String primaryUuid = getPrimaryStorageUuid();
+        if (Objects.equals(app.volumeUuid, primaryUuid)) {
+            return -1;
+        }
+        try {
+            return mStorageManager.getCacheQuotaBytes(primaryUuid, app.uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return total size in bytes of cached data on primary shared/external
+     * storage belonging to the calling app.
+     * <p>
+     * If primary shared/external storage is hosted on the same storage device
+     * as your private data, this method will return -1, since all data stored
+     * under {@link Context#getExternalCacheDir()} will be counted under
+     * {@link #getCacheQuotaBytes()}.
+     * <p class="note">
+     * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+     * then cached data for all packages in your shared UID is tracked together
+     * as a single unit.
+     * </p>
+     */
+    public long getExternalCacheSizeBytes() {
+        final ApplicationInfo app = mContext.getApplicationInfo();
+        final String primaryUuid = getPrimaryStorageUuid();
+        if (Objects.equals(app.volumeUuid, primaryUuid)) {
+            return -1;
+        }
+        try {
+            return mStorageManager.getCacheSizeBytes(primaryUuid, app.uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private static final String XATTR_ATOMIC = "user.atomic";
+    private static final String XATTR_TOMBSTONE = "user.tombstone";
+
+    /** {@hide} */
+    private static void setCacheBehavior(File path, String name, boolean enabled)
+            throws IOException {
+        if (!path.isDirectory()) {
+            throw new IOException("Cache behavior can only be set on directories");
+        }
+        if (enabled) {
+            try {
+                Os.setxattr(path.getAbsolutePath(), name,
+                        "1".getBytes(StandardCharsets.UTF_8), 0);
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        } else {
+            try {
+                Os.removexattr(path.getAbsolutePath(), name);
+            } catch (ErrnoException e) {
+                if (e.errno != OsConstants.ENODATA) {
+                    throw e.rethrowAsIOException();
+                }
+            }
+        }
+    }
+
+    /** {@hide} */
+    private static boolean isCacheBehavior(File path, String name) throws IOException {
+        try {
+            Os.getxattr(path.getAbsolutePath(), name);
+            return true;
+        } catch (ErrnoException e) {
+            if (e.errno != OsConstants.ENODATA) {
+                throw e.rethrowAsIOException();
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Enable or disable special cache behavior that treats this directory and
+     * its contents as an atomic unit.
+     * <p>
+     * When enabled and this directory is considered for automatic deletion by
+     * the OS, all contained files will either be deleted together, or not at
+     * all. This is useful when you have a directory that contains several
+     * related metadata files that depend on each other, such as movie file and
+     * a subtitle file.
+     * <p>
+     * When enabled, the <em>newest</em> {@link File#lastModified()} value of
+     * any contained files is considered the modified time of the entire
+     * directory.
+     * <p>
+     * This behavior can only be set on a directory, and it applies recursively
+     * to all contained files and directories.
+     */
+    public void setCacheBehaviorAtomic(File path, boolean atomic) throws IOException {
+        setCacheBehavior(path, XATTR_ATOMIC, atomic);
+    }
+
+    /**
+     * Read the current value set by
+     * {@link #setCacheBehaviorAtomic(File, boolean)}.
+     */
+    public boolean isCacheBehaviorAtomic(File path) throws IOException {
+        return isCacheBehavior(path, XATTR_ATOMIC);
+    }
+
+    /**
+     * Enable or disable special cache behavior that leaves deleted cache files
+     * intact as tombstones.
+     * <p>
+     * When enabled and a file contained in this directory is automatically
+     * deleted by the OS, the file will be truncated to have a length of 0 bytes
+     * instead of being fully deleted. This is useful if you need to distinguish
+     * between a file that was deleted versus one that never existed.
+     * <p>
+     * This behavior can only be set on a directory, and it applies recursively
+     * to all contained files and directories.
+     * <p class="note">
+     * Note: this behavior is ignored completely if the user explicitly requests
+     * that all cached data be cleared.
+     * </p>
+     */
+    public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
+        setCacheBehavior(path, XATTR_TOMBSTONE, tombstone);
+    }
+
+    /**
+     * Read the current value set by
+     * {@link #setCacheBehaviorTombstone(File, boolean)}.
+     */
+    public boolean isCacheBehaviorTombstone(File path) throws IOException {
+        return isCacheBehavior(path, XATTR_TOMBSTONE);
+    }
+
+    private final Object mFuseAppLoopLock = new Object();
+
+    @GuardedBy("mFuseAppLoopLock")
+    private @Nullable FuseAppLoop mFuseAppLoop = null;
+
     /// Consts to match the password types in cryptfs.h
     /** @hide */
     public static final int CRYPT_TYPE_PASSWORD = 0;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index a07aee5..1b512c6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8170,11 +8170,29 @@
         /**
          * The content:// style URI for this table.  Requests to this URI can be
          * performed on the UI thread because they are always unblocking.
+         *
+         * <p>Note when you listen on this URI (or any other sub-URIs), you'll be notified for
+         * regular contact change notifications too, which will be sent on the root URI.
+         * If you only want to be notified for provider status change notifications, listen on
+         * {@link #STATUS_CHANGE_NOTIFICATION_CONTENT_URI} instead.
          */
         public static final Uri CONTENT_URI =
                 Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
 
         /**
+         * URI to listen to provider status changes without listening to regular
+         * contact changes.  If a client only wants to monitor {@link ProviderStatus} with
+         * {@link android.app.job.JobScheduler}, then this URI should be used instead of
+         * {@link #CONTENT_URI}, because a job on {@link #CONTENT_URI} will also be invoked
+         * when contacts are changed.
+         *
+         * <p>Note this URI cannot be queried.  A query should be always made on
+         * {@link #CONTENT_URI}.
+         */
+        public static final Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI =
+                Uri.parse("content://com.android.contacts.provider_status");
+
+        /**
          * The MIME-type of {@link #CONTENT_URI} providing a directory of
          * settings.
          */
@@ -8201,6 +8219,13 @@
          * on the device.
          */
         public static final int STATUS_EMPTY = 2;
+
+        /**
+         * Timestamp (milliseconds since epoch) of when the provider's database was created.
+         *
+         * <P>Type: long
+         */
+        public static final String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     }
 
     /**
@@ -8768,7 +8793,14 @@
         /**
          * This is the intent that is fired when the contacts database is created. <p> The
          * READ_CONTACT permission is required to receive these broadcasts.
+         *
+         * <p>As of O, this broadcast will no longer be sent.  Applications can use
+         * use {@link android.app.job.JobScheduler} to monitor
+         * {@link ProviderStatus#STATUS_CHANGE_NOTIFICATION_CONTENT_URI}, and read
+         * {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to get when
+         * the contacts database was initialized.
          */
+        @Deprecated
         public static final String CONTACTS_DATABASE_CREATED =
                 "android.provider.Contacts.DATABASE_CREATED";
 
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index ded715f..a6e6fda 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -28,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ResolveInfo;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
@@ -422,6 +423,14 @@
         public static final int FLAG_SUPPORTS_SETTINGS = 1 << 11;
 
         /**
+         * Flag indicating that a Web link can be obtained for the document.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#createWebLinkIntent(PackageManager, Uri, Bundle)
+         */
+        public static final int FLAG_WEB_LINKABLE = 1 << 12;
+
+        /**
          * Flag indicating that a document is not complete, likely its
          * contents are being downloaded. Partial files cannot be opened,
          * copied, moved in the UI. But they can be deleted and retried
@@ -685,12 +694,20 @@
     public static final String METHOD_EJECT_ROOT = "android:ejectRoot";
     /** {@hide} */
     public static final String METHOD_FIND_DOCUMENT_PATH = "android:findDocumentPath";
+    /** {@hide} */
+    public static final String METHOD_CREATE_WEB_LINK_INTENT = "android:createWebLinkIntent";
 
     /** {@hide} */
     public static final String EXTRA_PARENT_URI = "parentUri";
     /** {@hide} */
     public static final String EXTRA_URI = "uri";
 
+    /**
+     * @see #createWebLinkIntent(ContentResolver, Uri, Bundle)
+     * {@hide}
+     */
+    public static final String EXTRA_OPTIONS = "options";
+
     private static final String PATH_ROOT = "root";
     private static final String PATH_RECENT = "recent";
     private static final String PATH_DOCUMENT = "document";
@@ -1401,6 +1418,85 @@
     }
 
     /**
+     * Creates an intent for obtaining a web link for the specified document.
+     *
+     * <p>Note, that due to internal limitations, if there is already a web link
+     * intent created for the specified document but with different options,
+     * then it may be overriden.
+     *
+     * <p>Providers are required to show confirmation UI for all new permissions granted
+     * for the linked document.
+     *
+     * <p>If list of recipients is known, then it should be passed in options as
+     * {@link Intent#EXTRA_EMAIL} as either a string or list of strings. Note, that
+     * this is just a hint for the provider, which can ignore the list. In either
+     * case the provider is required to show a UI for letting the user confirm
+     * any new permission grants.
+     *
+     * <p>Since this API may show a UI, it cannot be called from background.
+     *
+     * <p>In order to obtain the Web Link use code like this:
+     * <pre><code>
+     * void onSomethingHappened() {
+     *   IntentSender sender = DocumentsContract.createWebLinkIntent(<i>...</i>);
+     *   if (sender != null) {
+     *     startIntentSenderForResult(
+     *         DocumentsContract.createWebLinkIntent(<i>...</i>),
+     *         WEB_LINK_REQUEST_CODE,
+     *         null, 0, 0, 0, null);
+     *   }
+     * }
+     *
+     * <i>(...)</i>
+     *
+     * void onActivityResult(int requestCode, int resultCode, Intent data) {
+     *   if (requestCode == WEB_LINK_REQUEST_CODE && resultCode == RESULT_OK) {
+     *     Uri weblinkUri = data.getData();
+     *     <i>...</i>
+     *   }
+     * }
+     * </code></pre>
+     *
+     * @param uri uri for the document to create a link to.
+     * @param options Extra information for generating the link.
+     * @return an intent sender to obtain the web link, or null if the document
+     *      is not linkable, or creating the intent sender failed.
+     * @see DocumentsProvider#createWebLinkIntent(String, Bundle)
+     * @see Intent#EXTRA_EMAIL
+     */
+    public static IntentSender createWebLinkIntent(ContentResolver resolver, Uri uri,
+            Bundle options) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                uri.getAuthority());
+        try {
+            return createWebLinkIntent(client, uri, options);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to create a web link intent", e);
+            return null;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public static IntentSender createWebLinkIntent(ContentProviderClient client, Uri uri,
+            Bundle options) throws RemoteException {
+        final Bundle in = new Bundle();
+        in.putParcelable(DocumentsContract.EXTRA_URI, uri);
+
+        // Options may be provider specific, so put them in a separate bundle to
+        // avoid overriding the Uri.
+        if (options != null) {
+            in.putBundle(EXTRA_OPTIONS, options);
+        }
+
+        final Bundle out = client.call(METHOD_CREATE_WEB_LINK_INTENT, null, in);
+        return out.getParcelable(DocumentsContract.EXTRA_RESULT);
+    }
+
+    /**
      * Open the given image for thumbnail purposes, using any embedded EXIF
      * thumbnail if available, and providing orientation hints from the parent
      * image.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 8bc03ee..6170eb4 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -18,6 +18,7 @@
 
 import static android.provider.DocumentsContract.METHOD_COPY_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT;
+import static android.provider.DocumentsContract.METHOD_CREATE_WEB_LINK_INTENT;
 import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_EJECT_ROOT;
 import static android.provider.DocumentsContract.METHOD_FIND_DOCUMENT_PATH;
@@ -43,6 +44,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.UriMatcher;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
@@ -363,6 +365,33 @@
     }
 
     /**
+     * Creates an intent sender for a web link, if the document is web linkable.
+     * <p>
+     * Before any new permissions are granted for the linked document, a visible
+     * UI must be shown, so the user can explicitly confirm whether the permission
+     * grants are expected. The user must be able to cancel the operation.
+     * <p>
+     * Options passed as an argument may include a list of recipients, such
+     * as email addresses. The provider should reflect these options if possible,
+     * but it's acceptable to ignore them. In either case, confirmation UI must
+     * be shown before any new permission grants are granted.
+     * <p>
+     * It is all right to generate a web link without granting new permissions,
+     * if opening the link would result in a page for requesting permission
+     * access. If it's impossible then the operation must fail by throwing an exception.
+     *
+     * @param documentId the document to create a web link intent for.
+     * @param options additional information, such as list of recipients. Optional.
+     *
+     * @see DocumentsContract.Document#FLAG_WEB_LINKABLE
+     * @see android.app.PendingIntent#getIntentSender
+     */
+    public IntentSender createWebLinkIntent(String documentId, @Nullable Bundle options)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("createWebLink is not supported.");
+    }
+
+    /**
      * Return all roots currently provided. To display to users, you must define
      * at least one root. You should avoid making network requests to keep this
      * request fast.
@@ -900,6 +929,14 @@
                     newDocumentId);
             out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
+        } else if (METHOD_CREATE_WEB_LINK_INTENT.equals(method)) {
+            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+
+            final Bundle options = extras.getBundle(DocumentsContract.EXTRA_OPTIONS);
+            final IntentSender intentSender = createWebLinkIntent(documentId, options);
+
+            out.putParcelable(DocumentsContract.EXTRA_RESULT, intentSender);
+
         } else if (METHOD_RENAME_DOCUMENT.equals(method)) {
             enforceWritePermissionInner(documentUri, getCallingPackage(), null);
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 893e53c..71b9482 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -50,6 +50,7 @@
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.BatteryManager;
+import android.os.Binder;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.DropBoxManager;
@@ -286,6 +287,21 @@
             "android.settings.SECURITY_SETTINGS";
 
     /**
+     * Activity Action: Show settings to allow configuration of trusted external sources
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_EXTERNAL_SOURCES =
+            "android.settings.action.MANAGE_EXTERNAL_SOURCES";
+
+    /**
      * Activity Action: Show trusted credentials settings, opening to the user tab,
      * to allow management of installed credentials.
      * <p>
@@ -1581,6 +1597,24 @@
     // with a partial enable/disable state in multi-threaded situations.
     private static final Object mLocationSettingsLock = new Object();
 
+    // Used in system server calling uid workaround in call()
+    private static boolean sInSystemServer = false;
+    private static final Object sInSystemServerLock = new Object();
+
+    /** @hide */
+    public static void setInSystemServer() {
+        synchronized (sInSystemServerLock) {
+            sInSystemServer = true;
+        }
+    }
+
+    /** @hide */
+    public static boolean isInSystemServer() {
+        synchronized (sInSystemServerLock) {
+            return sInSystemServer;
+        }
+    }
+
     public static class SettingNotFoundException extends AndroidException {
         public SettingNotFoundException(String msg) {
             super(msg);
@@ -1789,7 +1823,23 @@
                             }
                         }
                     }
-                    Bundle b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
+                    Bundle b;
+                    // If we're in system server and in a binder transaction we need to clear the
+                    // calling uid. This works around code in system server that did not call
+                    // clearCallingIdentity, previously this wasn't needed because reading settings
+                    // did not do permission checking but thats no longer the case.
+                    // Long term this should be removed and callers should properly call
+                    // clearCallingIdentity or use a ContentResolver from the caller as needed.
+                    if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
+                        final long token = Binder.clearCallingIdentity();
+                        try {
+                            b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
+                        } finally {
+                            Binder.restoreCallingIdentity(token);
+                        }
+                    } else {
+                        b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
+                    }
                     if (b != null) {
                         String value = b.getString(Settings.NameValueTable.VALUE);
                         // Don't update our cache for reads of other users' data
@@ -1849,7 +1899,19 @@
             try {
                 Bundle queryArgs = ContentResolver.createSqlQueryBundle(
                         NAME_EQ_PLACEHOLDER, new String[]{name}, null);
-                c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs, null);
+                // Same workaround as above.
+                if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
+                                null);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                } else {
+                    c = cp.query(cr.getPackageName(), mUri, SELECT_VALUE_PROJECTION, queryArgs,
+                            null);
+                }
                 if (c == null) {
                     Log.w(TAG, "Can't get key " + name + " from " + mUri);
                     return null;
@@ -4006,6 +4068,22 @@
         }
 
         /**
+         * System settings which can be accessed by ephemeral apps.
+         * @hide
+         */
+        public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
+        static {
+            EPHEMERAL_SETTINGS.add(TEXT_AUTO_REPLACE);
+            EPHEMERAL_SETTINGS.add(TEXT_AUTO_CAPS);
+            EPHEMERAL_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
+            EPHEMERAL_SETTINGS.add(TEXT_SHOW_PASSWORD);
+            EPHEMERAL_SETTINGS.add(DATE_FORMAT);
+            EPHEMERAL_SETTINGS.add(FONT_SCALE);
+            EPHEMERAL_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
+            EPHEMERAL_SETTINGS.add(TIME_12_24);
+        }
+
+        /**
          * When to use Wi-Fi calling
          *
          * @see android.telephony.TelephonyManager.WifiCallingChoices
@@ -5313,6 +5391,21 @@
         public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
 
         /**
+         * Setting specifying if the accessibility shortcut dialog has been shown to this user.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN =
+                "accessibility_shortcut_dialog_shown";
+
+        /**
+         * Setting specifying the the accessibility service to be toggled via the accessibility
+         * shortcut. Must be its flattened {@link ComponentName}.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
+                "accessibility_shortcut_target_service";
+
+        /**
          * If touch exploration is enabled.
          */
         public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
@@ -6782,6 +6875,8 @@
             TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
             TOUCH_EXPLORATION_ENABLED,
             ACCESSIBILITY_ENABLED,
+            ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+            ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
             ACCESSIBILITY_SPEAK_PASSWORD,
             ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
             ACCESSIBILITY_CAPTIONING_PRESET,
@@ -6867,6 +6962,20 @@
         }
 
         /**
+         * Secure settings which can be accessed by ephemeral apps.
+         * @hide
+         */
+        public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
+        static {
+            EPHEMERAL_SETTINGS.add(ENABLED_ACCESSIBILITY_SERVICES);
+            EPHEMERAL_SETTINGS.add(ACCESSIBILITY_SPEAK_PASSWORD);
+            EPHEMERAL_SETTINGS.add(ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+
+            EPHEMERAL_SETTINGS.add(DEFAULT_INPUT_METHOD);
+            EPHEMERAL_SETTINGS.add(ENABLED_INPUT_METHODS);
+        }
+
+        /**
          * Helper method for determining if a location provider is enabled.
          *
          * @param cr the content resolver to use
@@ -7071,7 +7180,9 @@
          * Setting whether the global gesture for enabling accessibility is enabled.
          * If this gesture is enabled the user will be able to perfrom it to enable
          * the accessibility state without visiting the settings app.
+         *
          * @hide
+         * No longer used. Should be removed once all dependencies have been updated.
          */
         public static final String ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED =
                 "enable_accessibility_global_gesture_enabled";
@@ -7490,6 +7601,14 @@
                "hdmi_control_auto_device_off_enabled";
 
        /**
+        * The interval in milliseconds at which location requests will be throttled when they are
+        * coming from the background.
+        * @hide
+        */
+       public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
+                "location_background_throttle_interval_ms";
+
+       /**
         * Whether TV will switch to MHL port when a mobile device is plugged in.
         * (0 = false, 1 = true)
         * @hide
@@ -8020,6 +8139,16 @@
                 "network_recommendations_enabled";
 
         /**
+         * Value to specify if the Wi-Fi Framework should defer to
+         * {@link com.android.server.NetworkScoreService} for evaluating saved open networks.
+         *
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        @SystemApi
+        public static final String CURATE_SAVED_OPEN_NETWORKS = "curate_saved_open_networks";
+
+        /**
          * The number of milliseconds the {@link com.android.server.NetworkScoreService}
          * will give a recommendation request to complete before returning a default response.
          *
@@ -9372,7 +9501,6 @@
             DOCK_SOUNDS_ENABLED,
             CHARGING_SOUNDS_ENABLED,
             USB_MASS_STORAGE_ENABLED,
-            ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
             WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
             WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
             WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
@@ -9873,6 +10001,20 @@
          * @hide
          */
         public static final String CELL_ON = "cell_on";
+
+        /**
+         * Global settings which can be accessed by ephemeral apps.
+         * @hide
+         */
+        public static final Set<String> EPHEMERAL_SETTINGS = new ArraySet<>();
+        static {
+            EPHEMERAL_SETTINGS.add(WAIT_FOR_DEBUGGER);
+            EPHEMERAL_SETTINGS.add(DEVICE_PROVISIONED);
+            EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
+            EPHEMERAL_SETTINGS.add(DEVELOPMENT_FORCE_RTL);
+            EPHEMERAL_SETTINGS.add(EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
+        }
+
     }
 
     /**
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index c3cbcdc..a4b6807 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -30,6 +30,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.Voicemail;
+
 import java.util.List;
 
 /**
@@ -279,6 +280,48 @@
         public static final String LAST_MODIFIED = "last_modified";
 
         /**
+         * Flag to indicate the voicemail was backed up. The value will be 1 if backed up, 0 if
+         * not.
+         *
+         * <P>Type: INTEGER (boolean)</P>
+         *
+         * @hide
+         */
+        public static final String BACKED_UP = "backed_up";
+
+        /**
+         * Flag to indicate the voicemail was restored from a backup. The value will be 1 if
+         * restored, 0 if not.
+         *
+         * <P>Type: INTEGER (boolean)</P>
+         *
+         * @hide
+         */
+        public static final String RESTORED = "restored";
+
+        /**
+         * Flag to indicate the voicemail was marked as archived. Archived voicemail should not be
+         * deleted even if it no longer exist on the server. The value will be 1 if archived true, 0
+         * if not.
+         *
+         * <P>Type: INTEGER (boolean)</P>
+         *
+         * @hide
+         */
+        public static final String ARCHIVED = "archived";
+
+        /**
+         * Flag to indicate the voicemail is a OMTP voicemail handled by the {@link
+         * android.telephony.VisualVoicemailService}. The UI should only show OMTP voicemails from
+         * the current visual voicemail package.
+         *
+         * <P>Type: INTEGER (boolean)</P>
+         *
+         * @hide
+         */
+        public static final String IS_OMTP_VOICEMAIL = "is_omtp_voicmail";
+
+        /**
          * A convenience method to build voicemail URI specific to a source package by appending
          * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
          */
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index eb3d031..22f1bed 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -132,6 +132,8 @@
     public static final int KM_PURPOSE_DECRYPT = 1;
     public static final int KM_PURPOSE_SIGN = 2;
     public static final int KM_PURPOSE_VERIFY = 3;
+    public static final int KM_PURPOSE_DERIVE_KEY = 4;
+    public static final int KM_PURPOSE_WRAP_KEY = 5;
 
     // Key formats.
     public static final int KM_KEY_FORMAT_X509 = 0;
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index c2e980c..805d8e5 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -61,6 +61,19 @@
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
 
+    /**
+     * Name under which a AutoFillService component publishes information about itself.
+     * This meta-data should reference an XML resource containing a
+     * <code>&lt;{@link
+     * android.R.styleable#AutoFillService autofill-service}&gt;</code> tag.
+     * This is a a sample XML file configuring an AutoFillService:
+     * <pre> &lt;autofill-service
+     *     android:settingsActivity="foo.bar.SettingsActivity"
+     *     . . .
+     * /&gt;</pre>
+     */
+    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";
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
index fe21615..ab86580 100644
--- a/core/java/android/service/autofill/AutoFillServiceInfo.java
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -16,20 +16,34 @@
 package android.service.autofill;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 
 /** @hide */
 public final class AutoFillServiceInfo {
+    static final String TAG = "AutoFillServiceInfo";
 
     private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
             throws PackageManager.NameNotFoundException {
         try {
-            final ServiceInfo si =
-                    AppGlobals.getPackageManager().getServiceInfo(comp, 0, userHandle);
+            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(
+                    comp,
+                    PackageManager.GET_META_DATA,
+                    userHandle);
             if (si != null) {
                 return si;
             }
@@ -38,11 +52,21 @@
         throw new PackageManager.NameNotFoundException(comp.toString());
     }
 
+    @Nullable
     private String mParseError;
 
+    @Nullable
     private ServiceInfo mServiceInfo;
+    @Nullable
+    private String mSettingsActivity;
 
-    private  AutoFillServiceInfo(ServiceInfo si) {
+    public AutoFillServiceInfo(PackageManager pm, ComponentName comp, int userHandle)
+            throws PackageManager.NameNotFoundException {
+        this(pm, getServiceInfoOrThrow(comp, userHandle));
+    }
+
+    public AutoFillServiceInfo(PackageManager pm, ServiceInfo si)
+            throws PackageManager.NameNotFoundException{
         if (si == null) {
             mParseError = "Service not available";
             return;
@@ -53,19 +77,57 @@
             return;
         }
 
+        XmlResourceParser parser = null;
+        try {
+            parser = si.loadXmlMetaData(pm, AutoFillService.SERVICE_META_DATA);
+            if (parser == null) {
+                mParseError = "No " + AutoFillService.SERVICE_META_DATA
+                        + " meta-data for " + si.packageName;
+                return;
+            }
+
+            Resources res = pm.getResourcesForApplication(si.applicationInfo);
+
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+
+            String nodeName = parser.getName();
+            if (!"autofill-service".equals(nodeName)) {
+                mParseError = "Meta-data does not start with autofill-service tag";
+                return;
+            }
+
+            TypedArray array = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.AutoFillService);
+            mSettingsActivity = array.getString(
+                    com.android.internal.R.styleable.AutoFillService_settingsActivity);
+            array.recycle();
+        } catch (XmlPullParserException | IOException | PackageManager.NameNotFoundException e) {
+            mParseError = "Error parsing auto fill service meta-data: " + e;
+            Log.w(TAG, "error parsing auto fill service meta-data", e);
+            return;
+        } finally {
+            if (parser != null) parser.close();
+        }
         mServiceInfo = si;
     }
 
-    public AutoFillServiceInfo(ComponentName comp, int userHandle)
-            throws PackageManager.NameNotFoundException {
-        this(getServiceInfoOrThrow(comp, userHandle));
-    }
-
+    @Nullable
     public String getParseError() {
         return mParseError;
     }
 
+    @Nullable
     public ServiceInfo getServiceInfo() {
         return mServiceInfo;
     }
+
+    @Nullable
+    public String getSettingsActivity() {
+        return mSettingsActivity;
+    }
 }
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index f07d0d0..22b4d09 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -24,6 +24,7 @@
  */
 interface ITrustAgentService {
     oneway void onUnlockAttempt(boolean successful);
+    oneway void onUnlockLockout(int timeoutMs);
     oneway void onTrustTimeout();
     oneway void onDeviceLocked();
     oneway void onDeviceUnlocked();
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 9d7ffad..0d5177d 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -123,6 +123,7 @@
     private static final int MSG_TRUST_TIMEOUT = 3;
     private static final int MSG_DEVICE_LOCKED = 4;
     private static final int MSG_DEVICE_UNLOCKED = 5;
+    private static final int MSG_UNLOCK_LOCKOUT = 6;
 
     /**
      * Class containing raw data for a given configuration request.
@@ -151,6 +152,9 @@
                 case MSG_UNLOCK_ATTEMPT:
                     onUnlockAttempt(msg.arg1 != 0);
                     break;
+                case MSG_UNLOCK_LOCKOUT:
+                    onDeviceUnlockLockout(msg.arg1);
+                    break;
                 case MSG_CONFIGURE:
                     ConfigurationData data = (ConfigurationData) msg.obj;
                     boolean result = onConfigure(data.options);
@@ -226,6 +230,21 @@
     public void onDeviceUnlocked() {
     }
 
+    /**
+     * Called when the device enters a temporary unlock lockout.
+     *
+     * <p>This occurs when the user has consecutively failed to unlock the device too many times,
+     * and must wait until a timeout has passed to perform another attempt. The user may then only
+     * use strong authentication mechanisms (PIN, pattern or password) to unlock the device.
+     * Calls to {@link #grantTrust(CharSequence, long, int)} will be ignored until the user has
+     * unlocked the device and {@link #onDeviceUnlocked()} is called.
+     *
+     * @param timeoutMs The amount of time, in milliseconds, that needs to elapse before the user
+     *    can attempt to unlock the device again.
+     */
+    public void onDeviceUnlockLockout(long timeoutMs) {
+    }
+
     private void onError(String msg) {
         Slog.v(TAG, "Remote exception while " + msg);
     }
@@ -366,6 +385,11 @@
             mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0).sendToTarget();
         }
 
+        @Override
+        public void onUnlockLockout(int timeoutMs) {
+            mHandler.obtainMessage(MSG_UNLOCK_LOCKOUT, timeoutMs, 0).sendToTarget();
+        }
+
         @Override /* Binder API */
         public void onTrustTimeout() {
             mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
diff --git a/core/java/android/text/FontConfig.aidl b/core/java/android/text/FontConfig.aidl
new file mode 100644
index 0000000..17a5ca2
--- /dev/null
+++ b/core/java/android/text/FontConfig.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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.text;
+
+/** @hide */
+parcelable FontConfig;
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
new file mode 100644
index 0000000..df694ff
--- /dev/null
+++ b/core/java/android/text/FontConfig.java
@@ -0,0 +1,466 @@
+/*
+ * 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.text;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Font configuration descriptions for System fonts.
+ */
+public final class FontConfig implements Parcelable {
+    private final List<Family> mFamilies = new ArrayList<>();
+    private final List<Alias> mAliases = new ArrayList<>();
+
+    public FontConfig() {
+    }
+
+    public FontConfig(FontConfig config) {
+        for (int i = 0; i < config.mFamilies.size(); i++) {
+            mFamilies.add(new Family(config.mFamilies.get(i)));
+        }
+        mAliases.addAll(config.mAliases);
+    }
+
+    /**
+     * Returns the ordered list of families included in the system fonts.
+     */
+    public List<Family> getFamilies() {
+        return mFamilies;
+    }
+
+    /**
+     * Returns the list of aliases defined for the font families in the system fonts.
+     */
+    public List<Alias> getAliases() {
+        return mAliases;
+    }
+
+    /**
+     * @hide
+     */
+    public FontConfig(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flag) {
+        out.writeInt(mFamilies.size());
+        for (int i = 0; i < mFamilies.size(); i++) {
+            mFamilies.get(i).writeToParcel(out, flag);
+        }
+        out.writeInt(mAliases.size());
+        for (int i = 0; i < mAliases.size(); i++) {
+            mAliases.get(i).writeToParcel(out, flag);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void readFromParcel(Parcel in) {
+        int size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            mFamilies.add(new Family(in));
+        }
+        size = in.readInt();
+        for (int i = 0; i < size; i++) {
+            mAliases.add(new Alias(in));
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<FontConfig> CREATOR = new Parcelable.Creator() {
+        public FontConfig createFromParcel(Parcel in) {
+            return new FontConfig(in);
+        }
+        public FontConfig[] newArray(int size) {
+            return new FontConfig[size];
+        }
+    };
+
+    /**
+     * Class that holds information about a Font axis.
+     */
+    public static final class Axis implements Parcelable {
+        private final int mTag;
+        private final float mStyleValue;
+
+        public Axis(int tag, float styleValue) {
+            this.mTag = tag;
+            this.mStyleValue = styleValue;
+        }
+
+        /**
+         * Returns the variable font axis tag associated to this axis.
+         */
+        public int getTag() {
+            return mTag;
+        }
+
+        /**
+         * Returns the style value associated to the given axis for this font.
+         */
+        public float getStyleValue() {
+            return mStyleValue;
+        }
+
+        /**
+         * @hide
+         */
+        public Axis(Parcel in) {
+            mTag = in.readInt();
+            mStyleValue = in.readFloat();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeInt(mTag);
+            out.writeFloat(mStyleValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Axis> CREATOR = new Creator<Axis>() {
+            @Override
+            public Axis createFromParcel(Parcel in) {
+                return new Axis(in);
+            }
+
+            @Override
+            public Axis[] newArray(int size) {
+                return new Axis[size];
+            }
+        };
+    }
+
+    /**
+     * Class that holds information about a Font.
+     */
+    public static final class Font implements Parcelable {
+        private final String mFontName;
+        private final int mTtcIndex;
+        private final List<Axis> mAxes;
+        private final int mWeight;
+        private final boolean mIsItalic;
+        private ParcelFileDescriptor mFd;
+
+        public Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
+            mFontName = fontName;
+            mTtcIndex = ttcIndex;
+            mAxes = axes;
+            mWeight = weight;
+            mIsItalic = isItalic;
+            mFd = null;
+        }
+
+        public Font(Font origin) {
+            mFontName = origin.mFontName;
+            mTtcIndex = origin.mTtcIndex;
+            mAxes = new ArrayList<>(origin.mAxes);
+            mWeight = origin.mWeight;
+            mIsItalic = origin.mIsItalic;
+            if (origin.mFd != null) {
+                try {
+                    mFd = origin.mFd.dup();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        /**
+         * Returns the name associated by the system to this font.
+         */
+        public String getFontName() {
+            return mFontName;
+        }
+
+        /**
+         * Returns the index to be used to access this font when accessing a TTC file.
+         */
+        public int getTtcIndex() {
+            return mTtcIndex;
+        }
+
+        /**
+         * Returns the list of axes associated to this font.
+         */
+        public List<Axis> getAxes() {
+            return mAxes;
+        }
+
+        /**
+         * Returns the weight value for this font.
+         */
+        public int getWeight() {
+            return mWeight;
+        }
+
+        /**
+         * Returns whether this font is italic.
+         */
+        public boolean isItalic() {
+            return mIsItalic;
+        }
+
+        /**
+         * Returns a file descriptor to access the specified font. This should be closed after use.
+         */
+        public ParcelFileDescriptor getFd() {
+            return mFd;
+        }
+
+        /**
+         * @hide
+         */
+        public void setFd(ParcelFileDescriptor fd) {
+            mFd = fd;
+        }
+
+        /**
+         * @hide
+         */
+        public Font(Parcel in) {
+            mFontName = in.readString();
+            mTtcIndex = in.readInt();
+            final int numAxes = in.readInt();
+            mAxes = new ArrayList<>();
+            for (int i = 0; i < numAxes; i++) {
+                mAxes.add(new Axis(in));
+            }
+            mWeight = in.readInt();
+            mIsItalic = in.readInt() == 1;
+            if (in.readInt() == 1) { /* has FD */
+                mFd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+            } else {
+                mFd = null;
+            }
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeString(mFontName);
+            out.writeInt(mTtcIndex);
+            out.writeInt(mAxes.size());
+            for (int i = 0; i < mAxes.size(); i++) {
+                mAxes.get(i).writeToParcel(out, flag);
+            }
+            out.writeInt(mWeight);
+            out.writeInt(mIsItalic ? 1 : 0);
+            out.writeInt(mFd == null ? 0 : 1);
+            if (mFd != null) {
+                mFd.writeToParcel(out, flag);
+            }
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Font> CREATOR = new Creator<Font>() {
+            @Override
+            public Font createFromParcel(Parcel in) {
+                return new Font(in);
+            }
+
+            @Override
+            public Font[] newArray(int size) {
+                return new Font[size];
+            }
+        };
+    }
+
+    /**
+     * Class that holds information about a Font alias.
+     */
+    public static final class Alias implements Parcelable {
+        private final String mName;
+        private final String mToName;
+        private final int mWeight;
+
+        public Alias(String name, String toName, int weight) {
+            this.mName = name;
+            this.mToName = toName;
+            this.mWeight = weight;
+        }
+
+        /**
+         * Returns the new name for the alias.
+         */
+        public String getName() {
+            return mName;
+        }
+
+        /**
+         * Returns the existing name to which this alias points to.
+         */
+        public String getToName() {
+            return mToName;
+        }
+
+        /**
+         * Returns the weight associated with this alias.
+         */
+        public int getWeight() {
+            return mWeight;
+        }
+
+        /**
+         * @hide
+         */
+        public Alias(Parcel in) {
+            mName = in.readString();
+            mToName = in.readString();
+            mWeight = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeString(mName);
+            out.writeString(mToName);
+            out.writeInt(mWeight);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Alias> CREATOR = new Creator<Alias>() {
+            @Override
+            public Alias createFromParcel(Parcel in) {
+                return new Alias(in);
+            }
+
+            @Override
+            public Alias[] newArray(int size) {
+                return new Alias[size];
+            }
+        };
+    }
+
+    /**
+     * Class that holds information about a Font family.
+     */
+    public static final class Family implements Parcelable {
+        private final String mName;
+        private final List<Font> mFonts;
+        private final String mLanguage;
+        private final String mVariant;
+
+        public Family(String name, List<Font> fonts, String language, String variant) {
+            this.mName = name;
+            this.mFonts = fonts;
+            this.mLanguage = language;
+            this.mVariant = variant;
+        }
+
+        public Family(Family origin) {
+            this.mName = origin.mName;
+            this.mLanguage = origin.mLanguage;
+            this.mVariant = origin.mVariant;
+            this.mFonts = new ArrayList<>();
+            for (int i = 0; i < origin.mFonts.size(); i++) {
+                mFonts.add(new Font(origin.mFonts.get(i)));
+            }
+        }
+
+        /**
+         * Returns the name given by the system to this font family.
+         */
+        public String getName() {
+            return mName;
+        }
+
+        /**
+         * Returns the list of fonts included in this family.
+         */
+        public List<Font> getFonts() {
+            return mFonts;
+        }
+
+        /**
+         * Returns the language for this family. May be null.
+         */
+        public String getLanguage() {
+            return mLanguage;
+        }
+
+        /**
+         * Returns the font variant for this family, e.g. "elegant" or "compact". May be null.
+         */
+        public String getVariant() {
+            return mVariant;
+        }
+
+        /**
+         * @hide
+         */
+        public Family(Parcel in) {
+            mName = in.readString();
+            final int size = in.readInt();
+            mFonts = new ArrayList<>();
+            for (int i = 0; i < size; i++) {
+                mFonts.add(new Font(in));
+            }
+            mLanguage = in.readString();
+            mVariant = in.readString();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flag) {
+            out.writeString(mName);
+            out.writeInt(mFonts.size());
+            for (int i = 0; i < mFonts.size(); i++) {
+                mFonts.get(i).writeToParcel(out, flag);
+            }
+            out.writeString(mLanguage);
+            out.writeString(mVariant);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final Creator<Family> CREATOR = new Creator<Family>() {
+            @Override
+            public Family createFromParcel(Parcel in) {
+                return new Family(in);
+            }
+
+            @Override
+            public Family[] newArray(int size) {
+                return new Family[size];
+            }
+        };
+    }
+}
diff --git a/core/java/android/text/FontManager.java b/core/java/android/text/FontManager.java
new file mode 100644
index 0000000..b61cbf3
--- /dev/null
+++ b/core/java/android/text/FontManager.java
@@ -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.
+ */
+
+package android.text;
+
+import android.os.RemoteException;
+
+import com.android.internal.font.IFontManager;
+
+/**
+ * Interact with the Font service.
+ */
+public final class FontManager {
+    private static final String TAG = "FontManager";
+
+    private final IFontManager mService;
+
+    /**
+     * @hide
+     */
+    public FontManager(IFontManager service) {
+        mService = service;
+    }
+
+    /**
+     * Retrieve the system fonts data. This loads the fonts.xml data if needed and loads all system
+     * fonts in to memory, providing file descriptors for them.
+     */
+    public FontConfig getSystemFonts() {
+        try {
+            return mService.getSystemFonts();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/text/TextAssistant.java b/core/java/android/text/TextAssistant.java
deleted file mode 100644
index b044981..0000000
--- a/core/java/android/text/TextAssistant.java
+++ /dev/null
@@ -1,56 +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.text;
-
-/**
- * Interface for providing text assistant features.
- */
-public interface TextAssistant {
-
-    /**
-     * NO_OP TextAssistant. This will act as the default TextAssistant until we implement a
-     * TextClassificationManager.
-     * @hide
-     */
-    TextAssistant NO_OP = new TextAssistant() {
-
-        private final TextSelection mTextSelection = new TextSelection();
-
-        @Override
-        public TextSelection suggestSelection(
-                CharSequence text, int selectionStartIndex, int selectionEndIndex) {
-            mTextSelection.mStartIndex = selectionStartIndex;
-            mTextSelection.mEndIndex = selectionEndIndex;
-            return mTextSelection;
-        }
-
-        @Override
-        public void addLinks(Spannable text, int linkMask) {}
-    };
-
-    /**
-     * Returns suggested text selection indices, recognized types and their associated confidence
-     * scores. The selections are ordered from highest to lowest scoring.
-     */
-    TextSelection suggestSelection(
-            CharSequence text, int selectionStartIndex, int selectionEndIndex);
-
-    /**
-     * Adds assistance clickable spans to the provided text.
-     */
-    void addLinks(Spannable text, int linkMask);
-}
diff --git a/core/java/android/text/TextClassification.java b/core/java/android/text/TextClassification.java
deleted file mode 100644
index bb226da..0000000
--- a/core/java/android/text/TextClassification.java
+++ /dev/null
@@ -1,40 +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.text;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Information about entities that a specific piece of text is classified as.
- */
-public class TextClassification {
-
-    /** @hide */
-    public static final TextClassification NO_OP = new TextClassification();
-
-    private Map<String, Float> mTypeConfidence = Collections.unmodifiableMap(Collections.EMPTY_MAP);
-
-    /**
-     * Returns a map of text classification types to their respective confidence scores.
-     * The scores range from 0 (low confidence) to 1 (high confidence). The items are ordered from
-     * high scoring items to low scoring items.
-     */
-    public Map<String, Float> getTypeConfidence() {
-        return mTypeConfidence;
-    }
-}
diff --git a/core/java/android/text/TextClassificationManager.java b/core/java/android/text/TextClassificationManager.java
deleted file mode 100644
index d4548f0..0000000
--- a/core/java/android/text/TextClassificationManager.java
+++ /dev/null
@@ -1,62 +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.text;
-
-import android.annotation.NonNull;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Interface to the text classification service.
- * This class uses machine learning techniques to infer things about text.
- * Unless otherwise stated, methods of this class are blocking operations and should most likely not
- * be called on the UI thread.
- *
- * <p> You do not instantiate this class directly; instead, retrieve it through
- * {@link android.content.Context#getSystemService}.
- *
- * The TextClassificationManager serves as the default TextAssistant if none has been set.
- * @see android.app.Activity#setTextAssistant(TextAssistant).
- */
-public final class TextClassificationManager implements TextAssistant {
-    // TODO: Consider not making this class implement TextAssistant.
-
-    /** @hide */
-    public TextClassificationManager() {}
-
-    /**
-     * Returns information containing languages that were detected in the provided text.
-     * This is a blocking operation and should most likely not be called on the UI thread.
-     */
-    public List<TextLanguage> detectLanguages(@NonNull CharSequence text) {
-        // TODO: Implement this using the cld3 library.
-        return Collections.emptyList();
-    }
-
-    @Override
-    public TextSelection suggestSelection(
-            @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex) {
-        // TODO: Implement.
-        return TextAssistant.NO_OP.suggestSelection(text, selectionStartIndex, selectionEndIndex);
-    }
-
-    @Override
-    public void addLinks(@NonNull Spannable text, int linkMask) {
-        // TODO: Implement.
-    }
-}
diff --git a/core/java/android/text/TextLanguage.java b/core/java/android/text/TextLanguage.java
deleted file mode 100644
index eb834f1..0000000
--- a/core/java/android/text/TextLanguage.java
+++ /dev/null
@@ -1,85 +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.text;
-
-import android.annotation.NonNull;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-/**
- * Specifies detected languages for a section of text indicated by a start and end index.
- */
-public final class TextLanguage {
-
-    private final int mStartIndex;
-    private final int mEndIndex;
-    private final Map<String, Float> mLanguageConfidence;
-
-    /**
-     * Initializes a TextLanguage object.
-     *
-     * @param startIndex the start index of the detected languages in the text provided to generate
-     *      this object.
-     * @param endIndex the end index of the detected languages in the text provided to generate this
-     *      object.
-     * @param languageConfidence a map of detected language to confidence score. The language string
-     *      is a BCP-47 language tag.
-     * @throws NullPointerException if languageConfidence is null or contains a null key or value.
-     */
-    public TextLanguage(int startIndex, int endIndex,
-            @NonNull Map<String, Float> languageConfidence) {
-        mStartIndex = startIndex;
-        mEndIndex = endIndex;
-
-        Map<String, Float> map = new LinkedHashMap<>();
-        Preconditions.checkNotNull(languageConfidence).entrySet().stream()
-                .sorted(Map.Entry.comparingByValue())
-                .forEach(entry -> map.put(
-                        Preconditions.checkNotNull(entry.getKey()),
-                        Preconditions.checkNotNull(entry.getValue())));
-        mLanguageConfidence = Collections.unmodifiableMap(map);
-    }
-
-    /**
-     * Returns the start index of the detected languages in the text provided to generate this
-     * object.
-     */
-    public int getStartIndex() {
-        return mStartIndex;
-    }
-
-    /**
-     * Returns the end index of the detected languages in the text provided to generate this object.
-     */
-    public int getEndIndex() {
-        return mEndIndex;
-    }
-
-    /**
-     * Returns an unmodifiable map of detected language to confidence score. The map entries are
-     * ordered from high confidence score (1) to low confidence score (0). The language string is a
-     * BCP-47 language tag.
-     */
-    @NonNull
-    public Map<String, Float> getLanguageConfidence() {
-        return mLanguageConfidence;
-    }
-}
diff --git a/core/java/android/text/TextSelection.java b/core/java/android/text/TextSelection.java
deleted file mode 100644
index 9400458..0000000
--- a/core/java/android/text/TextSelection.java
+++ /dev/null
@@ -1,51 +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.text;
-
-/**
- * Text selection information.
- */
-public class TextSelection {
-
-    /** @hide */
-    int mStartIndex;
-    /** @hide */
-    int mEndIndex;
-
-    private TextClassification mTextClassification = TextClassification.NO_OP;
-
-    /**
-     * Returns the start index of the text selection.
-     */
-    public int getSelectionStartIndex() {
-        return mStartIndex;
-    }
-
-    /**
-     * Returns the end index of the text selection.
-     */
-    public int getSelectionEndIndex() {
-        return mEndIndex;
-    }
-
-    /**
-     * Returns information about what the text selection is classified as.
-     */
-    public TextClassification getTextClassification() {
-        return mTextClassification;
-    }
-}
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
new file mode 100644
index 0000000..7103e6d
--- /dev/null
+++ b/core/java/android/util/ByteStringUtils.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+/**
+ * A utility class for common byte array to hex string operations and vise versa.
+ *
+ * @hide
+ */
+public final class ByteStringUtils {
+  private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+  private ByteStringUtils() {
+    /* hide constructor */
+  }
+
+  /**
+   * Returns the hex encoded string representation of bytes.
+   * @param bytes Byte array to encode.
+   * @return Hex encoded string representation of bytes.
+   */
+  public static String toString(byte[] bytes) {
+    if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
+      return null;
+    }
+
+    final int byteLength = bytes.length;
+    final int charCount = 2 * byteLength;
+    final char[] chars = new char[charCount];
+
+    for (int i = 0; i < byteLength; i++) {
+      final int byteHex = bytes[i] & 0xFF;
+      chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
+      chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
+    }
+    return new String(chars);
+  }
+
+  /**
+   * Returns the decoded byte array representation of str.
+   * @param str Hex encoded string to decode.
+   * @return Decoded byte array representation of str.
+   */
+  public static byte[] toByteArray(String str) {
+    if (str == null || str.length() == 0 || str.length() % 2 != 0) {
+      return null;
+    }
+
+    final char[] chars = str.toCharArray();
+    final int charLength = chars.length;
+    final byte[] bytes = new byte[charLength / 2];
+
+    for (int i = 0; i < bytes.length; i++) {
+      bytes[i] =
+          (byte)(((getIndex(chars[i * 2]) << 4) & 0xF0) | (getIndex(chars[i * 2 + 1]) & 0x0F));
+    }
+    return bytes;
+  }
+
+  private static int getIndex(char c) {
+    for (int i = 0; i < HEX_ARRAY.length; i++) {
+      if (HEX_ARRAY[i] == c) {
+        return i;
+      }
+    }
+    return -1;
+  }
+}
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 79d16fb..92c70bd 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import android.annotation.SystemApi;
+
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
@@ -253,6 +255,19 @@
             throws IOException;
 
     /**
+     * Read events from the log, filtered by type, blocking until logs are about to be overwritten.
+     * @param tags to search for
+     * @param timestamp timestamp allow logs before this time to be overwritten.
+     * @param output container to add events into
+     * @throws IOException if something goes wrong reading events
+     * @hide
+     */
+    @SystemApi
+    public static native void readEventsOnWrapping(int[] tags, long timestamp,
+            Collection<Event> output)
+            throws IOException;
+
+    /**
      * Get the name associated with an event type tag code.
      * @param tag code to look up
      * @return the name of the tag, or null if no tag has that number
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index f5d515d..da0b609 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import android.os.ParcelableException;
+
 import java.io.IOException;
 
 /**
@@ -24,19 +26,13 @@
  * @hide
  */
 public class ExceptionUtils {
-    // TODO: longer term these should be replaced with first-class
-    // Parcel.read/writeException() and AIDL support, but for now do this using
-    // a nasty hack.
-
-    private static final String PREFIX_IO = "\u2603";
-
     public static RuntimeException wrap(IOException e) {
-        throw new IllegalStateException(PREFIX_IO + e.getMessage());
+        throw new ParcelableException(e);
     }
 
     public static void maybeUnwrapIOException(RuntimeException e) throws IOException {
-        if ((e instanceof IllegalStateException) && e.getMessage().startsWith(PREFIX_IO)) {
-            throw new IOException(e.getMessage().substring(PREFIX_IO.length()));
+        if (e instanceof ParcelableException) {
+            ((ParcelableException) e).maybeRethrow(IOException.class);
         }
     }
 
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index 6531aef..3181979 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -30,7 +30,6 @@
  * @hide
  */
 public final class PackageUtils {
-    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 
     private PackageUtils() {
         /* hide constructor */
@@ -81,16 +80,6 @@
 
         messageDigest.update(data);
 
-        final byte[] digest = messageDigest.digest();
-        final int digestLength = digest.length;
-        final int charCount = 2 * digestLength;
-
-        final char[] chars = new char[charCount];
-        for (int i = 0; i < digestLength; i++) {
-            final int byteHex = digest[i] & 0xFF;
-            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
-            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
-        }
-        return new String(chars);
+        return ByteStringUtils.toString(messageDigest.digest());
     }
 }
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index b37ea8e..105cc47 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -292,7 +292,7 @@
     public static final int STATE_VR = 5;
 
     /* The color mode constants defined below must be kept in sync with the ones in
-     * system/graphics.h */
+     * system/core/include/system/graphics-base.h */
 
     /**
      * Display color mode: The current color mode is unknown or invalid.
@@ -306,11 +306,24 @@
      */
     public static final int COLOR_MODE_DEFAULT = 0;
 
-    /**
-     * Display color mode: SRGB
-     * @hide
-     */
+    /** @hide */
+    public static final int COLOR_MODE_BT601_625 = 1;
+    /** @hide */
+    public static final int COLOR_MODE_BT601_625_UNADJUSTED = 2;
+    /** @hide */
+    public static final int COLOR_MODE_BT601_525 = 3;
+    /** @hide */
+    public static final int COLOR_MODE_BT601_525_UNADJUSTED = 4;
+    /** @hide */
+    public static final int COLOR_MODE_BT709 = 5;
+    /** @hide */
+    public static final int COLOR_MODE_DCI_P3 = 6;
+    /** @hide */
     public static final int COLOR_MODE_SRGB = 7;
+    /** @hide */
+    public static final int COLOR_MODE_ADOBE_RGB = 8;
+    /** @hide */
+    public static final int COLOR_MODE_DISPLAY_P3 = 9;
 
     /**
      * Internal method to create a display.
@@ -745,6 +758,8 @@
 
     /**
      * Returns the display's HDR capabilities.
+     *
+     * @see #isHdr()
      */
     public HdrCapabilities getHdrCapabilities() {
         synchronized (this) {
@@ -754,6 +769,35 @@
     }
 
     /**
+     * Returns whether this display supports any HDR type.
+     *
+     * @see #getHdrCapabilities()
+     * @see HdrCapabilities#getSupportedHdrTypes()
+     */
+    public boolean isHdr() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            int[] types = mDisplayInfo.hdrCapabilities.getSupportedHdrTypes();
+            return types != null && types.length > 0;
+        }
+    }
+
+    /**
+     * Returns whether this display can be used to display wide color gamut content.
+     */
+    public boolean isWideColorGamut() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            for (int colorMode : mDisplayInfo.supportedColorModes) {
+                if (colorMode == COLOR_MODE_DCI_P3 || colorMode > COLOR_MODE_SRGB) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
      * Gets the supported color modes of this device.
      * @hide
      */
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index a07a7ef..41a13cf 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -16,16 +16,12 @@
 
 package android.view;
 
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_CLUSTER;
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_SECTION;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.util.ArrayMap;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.view.View.KeyboardNavigationGroupType;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -110,31 +106,28 @@
     }
 
     /**
-     * Find the root of the next keyboard navigation group after the current one. The group type can
-     * be either a cluster or a section.
-     * @param groupType Type of the keyboard navigation group
+     * Find the root of the next keyboard navigation cluster after the current one.
      * @param root The view tree to look inside. Cannot be null
-     * @param currentGroup The starting point of the search. Null means the default group
+     * @param currentCluster The starting point of the search. Null means the default cluster
      * @param direction Direction to look
-     * @return The next group, or null if none exists
+     * @return The next cluster, or null if none exists
      */
-    public View findNextKeyboardNavigationGroup(
-            @KeyboardNavigationGroupType int groupType,
+    public View findNextKeyboardNavigationCluster(
             @NonNull View root,
-            @Nullable View currentGroup,
+            @Nullable View currentCluster,
             int direction) {
         View next = null;
 
-        final ArrayList<View> groups = mTempList;
+        final ArrayList<View> clusters = mTempList;
         try {
-            groups.clear();
-            root.addKeyboardNavigationGroups(groupType, groups, direction);
-            if (!groups.isEmpty()) {
-                next = findNextKeyboardNavigationGroup(
-                        groupType, root, currentGroup, groups, direction);
+            clusters.clear();
+            root.addKeyboardNavigationClusters(clusters, direction);
+            if (!clusters.isEmpty()) {
+                next = findNextKeyboardNavigationCluster(
+                        root, currentCluster, clusters, direction);
             }
         } finally {
-            groups.clear();
+            clusters.clear();
         }
         return next;
     }
@@ -207,25 +200,22 @@
         }
     }
 
-    private View findNextKeyboardNavigationGroup(
-            @KeyboardNavigationGroupType int groupType,
+    private View findNextKeyboardNavigationCluster(
             View root,
-            View currentGroup,
-            List<View> groups,
+            View currentCluster,
+            List<View> clusters,
             int direction) {
-        final int count = groups.size();
+        final int count = clusters.size();
 
         switch (direction) {
             case View.FOCUS_FORWARD:
             case View.FOCUS_DOWN:
             case View.FOCUS_RIGHT:
-                return getNextKeyboardNavigationGroup(
-                        groupType, root, currentGroup, groups, count);
+                return getNextKeyboardNavigationCluster(root, currentCluster, clusters, count);
             case View.FOCUS_BACKWARD:
             case View.FOCUS_UP:
             case View.FOCUS_LEFT:
-                return getPreviousKeyboardNavigationGroup(
-                        groupType, root, currentGroup, groups, count);
+                return getPreviousKeyboardNavigationCluster(root, currentCluster, clusters, count);
             default:
                 throw new IllegalArgumentException("Unknown direction: " + direction);
         }
@@ -331,70 +321,50 @@
         return null;
     }
 
-    private static View getNextKeyboardNavigationGroup(
-            @KeyboardNavigationGroupType int groupType,
+    private static View getNextKeyboardNavigationCluster(
             View root,
-            View currentGroup,
-            List<View> groups,
+            View currentCluster,
+            List<View> clusters,
             int count) {
-        if (currentGroup == null) {
-            // The current group is the default one.
-            // The next group after the default one is the first one.
-            // Note that the caller guarantees that 'group' is not empty.
-            return groups.get(0);
+        if (currentCluster == null) {
+            // The current cluster is the default one.
+            // The next cluster after the default one is the first one.
+            // Note that the caller guarantees that 'clusters' is not empty.
+            return clusters.get(0);
         }
 
-        final int position = groups.lastIndexOf(currentGroup);
+        final int position = clusters.lastIndexOf(currentCluster);
         if (position >= 0 && position + 1 < count) {
-            // Return the next non-default group if we can find it.
-            return groups.get(position + 1);
+            // Return the next non-default cluster if we can find it.
+            return clusters.get(position + 1);
         }
 
-        switch (groupType) {
-            case KEYBOARD_NAVIGATION_GROUP_CLUSTER:
-                // The current cluster is the last one. The next one is the default one, i.e. the
-                // root.
-                return root;
-            case KEYBOARD_NAVIGATION_GROUP_SECTION:
-                // There is no "default section", hence returning the first one.
-                return groups.get(0);
-            default:
-                throw new IllegalArgumentException(
-                        "Unknown keyboard navigation group type: " + groupType);
-        }
+        // The current cluster is the last one. The next one is the default one, i.e. the
+        // root.
+        return root;
     }
 
-    private static View getPreviousKeyboardNavigationGroup(
-            @KeyboardNavigationGroupType int groupType,
+    private static View getPreviousKeyboardNavigationCluster(
             View root,
-            View currentGroup,
-            List<View> groups,
+            View currentCluster,
+            List<View> clusters,
             int count) {
-        if (currentGroup == null) {
-            // The current group is the default one.
-            // The previous group before the default one is the last one.
-            // Note that the caller guarantees that 'groups' is not empty.
-            return groups.get(count - 1);
+        if (currentCluster == null) {
+            // The current cluster is the default one.
+            // The previous cluster before the default one is the last one.
+            // Note that the caller guarantees that 'clusters' is not empty.
+            return clusters.get(count - 1);
         }
 
-        final int position = groups.indexOf(currentGroup);
+        final int position = clusters.indexOf(currentCluster);
         if (position > 0) {
-            // Return the previous non-default group if we can find it.
-            return groups.get(position - 1);
+            // Return the previous non-default cluster if we can find it.
+            return clusters.get(position - 1);
         }
 
-        switch (groupType) {
-            case KEYBOARD_NAVIGATION_GROUP_CLUSTER:
-                // The current cluster is the first one. The previous one is the default one, i.e.
-                // the root.
-                return root;
-            case KEYBOARD_NAVIGATION_GROUP_SECTION:
-                // There is no "default section", hence returning the last one.
-                return groups.get(count - 1);
-            default:
-                throw new IllegalArgumentException(
-                        "Unknown keyboard navigation group type: " + groupType);
-        }
+        // The current cluster is the first one. The previous one is the default one, i.e.
+        // the root.
+        return root;
     }
 
     /**
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index f3f3d40..7a5c65f 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -335,7 +335,7 @@
         private ActionProvider itemActionProvider;
 
         private CharSequence itemContentDescription;
-        private CharSequence itemTooltip;
+        private CharSequence itemTooltipText;
 
         private static final int defaultGroupId = NO_ID;
         private static final int defaultItemId = NO_ID;
@@ -429,7 +429,7 @@
 
             itemContentDescription =
                     a.getText(com.android.internal.R.styleable.MenuItem_contentDescription);
-            itemTooltip = a.getText(com.android.internal.R.styleable.MenuItem_tooltip);
+            itemTooltipText = a.getText(com.android.internal.R.styleable.MenuItem_tooltipText);
 
             a.recycle();
 
@@ -495,7 +495,7 @@
             }
 
             item.setContentDescription(itemContentDescription);
-            item.setTooltip(itemTooltip);
+            item.setTooltipText(itemTooltipText);
         }
 
         public MenuItem addItem() {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 5ced765..3f8d089 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -621,9 +621,9 @@
     /**
      * Change the tooltip text associated with this menu item.
      *
-     * @param tooltip The new tooltip text.
+     * @param tooltipText The new tooltip text.
      */
-    default MenuItem setTooltip(CharSequence tooltip) {
+    default MenuItem setTooltipText(CharSequence tooltipText) {
         return this;
     }
 
@@ -632,7 +632,7 @@
      *
      * @return The tooltip text.
      */
-    default CharSequence getTooltip() {
+    default CharSequence getTooltipText() {
         return null;
     }
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f3ebcb4..b0826a8 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -360,6 +360,7 @@
     void destroy() {
         mInitialized = false;
         updateEnabledState(null);
+        mRootNode.discardDisplayList();
         nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
     }
 
@@ -491,20 +492,12 @@
      */
     void destroyHardwareResources(View view) {
         destroyResources(view);
+        mRootNode.discardDisplayList();
         nDestroyHardwareResources(mNativeProxy);
     }
 
     private static void destroyResources(View view) {
         view.destroyHardwareResources();
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyResources(group.getChildAt(i));
-            }
-        }
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9d1af50..13555f4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1252,14 +1252,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward
 
-    /** @hide */
-    @IntDef({
-            KEYBOARD_NAVIGATION_GROUP_CLUSTER,
-            KEYBOARD_NAVIGATION_GROUP_SECTION
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface KeyboardNavigationGroupType {}
-
     /**
      * Use with {@link #focusSearch(int)}. Move focus to the previous selectable
      * item.
@@ -1293,18 +1285,6 @@
     public static final int FOCUS_DOWN = 0x00000082;
 
     /**
-     * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard
-     * navigation cluster.
-     */
-    public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1;
-
-    /**
-     * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard
-     * navigation section.
-     */
-    public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2;
-
-    /**
      * Bits of {@link #getMeasuredWidthAndState()} and
      * {@link #getMeasuredWidthAndState()} that provide the actual measured size.
      */
@@ -2500,7 +2480,7 @@
      *                    1              PFLAG3_SCROLL_INDICATOR_END
      *                   1               PFLAG3_ASSIST_BLOCKED
      *                  1                PFLAG3_CLUSTER
-     *                 1                 PFLAG3_SECTION
+     *                 x                 * NO LONGER NEEDED, SHOULD BE REUSED *
      *                1                  PFLAG3_FINGER_DOWN
      *               1                   PFLAG3_FOCUSED_BY_DEFAULT
      *           xxxx                    * NO LONGER NEEDED, SHOULD BE REUSED *
@@ -2710,14 +2690,6 @@
     private static final int PFLAG3_CLUSTER = 0x8000;
 
     /**
-     * Flag indicating that the view is a root of a keyboard navigation section.
-     *
-     * @see #isKeyboardNavigationSection()
-     * @see #setKeyboardNavigationSection(boolean)
-     */
-    private static final int PFLAG3_SECTION = 0x10000;
-
-    /**
      * Indicates that the user is currently touching the screen.
      * Currently used for the tooltip positioning only.
      */
@@ -3718,7 +3690,7 @@
          * Text to be displayed in a tooltip popup.
          */
         @Nullable
-        CharSequence mTooltip;
+        CharSequence mTooltipText;
 
         /**
          * View-relative position of the tooltip anchor point.
@@ -3807,11 +3779,6 @@
      */
     int mNextClusterForwardId = View.NO_ID;
 
-    /**
-     * User-specified next keyboard navigation section.
-     */
-    int mNextSectionForwardId = View.NO_ID;
-
     private CheckForLongPress mPendingCheckForLongPress;
     private CheckForTap mPendingCheckForTap = null;
     private PerformClick mPerformClick;
@@ -4622,9 +4589,6 @@
                 case R.styleable.View_nextClusterForward:
                     mNextClusterForwardId = a.getResourceId(attr, View.NO_ID);
                     break;
-                case R.styleable.View_nextSectionForward:
-                    mNextSectionForwardId = a.getResourceId(attr, View.NO_ID);
-                    break;
                 case R.styleable.View_minWidth:
                     mMinWidth = a.getDimensionPixelSize(attr, 0);
                     break;
@@ -4761,19 +4725,14 @@
                         forceHasOverlappingRendering(a.getBoolean(attr, true));
                     }
                     break;
-                case R.styleable.View_tooltip:
-                    setTooltip(a.getText(attr));
+                case R.styleable.View_tooltipText:
+                    setTooltipText(a.getText(attr));
                     break;
                 case R.styleable.View_keyboardNavigationCluster:
                     if (a.peekValue(attr) != null) {
                         setKeyboardNavigationCluster(a.getBoolean(attr, true));
                     }
                     break;
-                case R.styleable.View_keyboardNavigationSection:
-                    if (a.peekValue(attr) != null) {
-                        setKeyboardNavigationSection(a.getBoolean(attr, true));
-                    }
-                    break;
                 case R.styleable.View_focusedByDefault:
                     if (a.peekValue(attr) != null) {
                         setFocusedByDefault(a.getBoolean(attr, true));
@@ -6934,8 +6893,7 @@
                 & (View.AUTO_FILL_FLAG_TYPE_FILL
                         | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
         final int id = mID;
-        if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
-                && (id&0x0000ffff) != 0) {
+        if (id != NO_ID && !isViewIdGenerated(id)) {
             String pkg, type, entry;
             try {
                 final Resources res = getResources();
@@ -8044,28 +8002,6 @@
     }
 
     /**
-     * Gets the id of the root of the next keyboard navigation section.
-     * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should
-     * decide automatically.
-     *
-     * @attr ref android.R.styleable#View_nextSectionForward
-     */
-    public int getNextSectionForwardId() {
-        return mNextSectionForwardId;
-    }
-
-    /**
-     * Sets the id of the view to use as the root of the next keyboard navigation section.
-     * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should
-     * decide automatically.
-     *
-     * @attr ref android.R.styleable#View_nextSectionForward
-     */
-    public void setNextSectionForwardId(int nextSectionForwardId) {
-        mNextSectionForwardId = nextSectionForwardId;
-    }
-
-    /**
      * Returns the visibility of this view and all of its ancestors
      *
      * @return True if this view and all of its ancestors are {@link #VISIBLE}
@@ -9187,49 +9123,11 @@
     }
 
     /**
-     * Returns whether this View is a root of a keyboard navigation section.
-     *
-     * @return True if this view is a root of a section, or false otherwise.
-     * @attr ref android.R.styleable#View_keyboardNavigationSection
-     */
-    @ViewDebug.ExportedProperty(category = "keyboardNavigationSection")
-    public final boolean isKeyboardNavigationSection() {
-        return (mPrivateFlags3 & PFLAG3_SECTION) != 0;
-    }
-
-    /**
-     * Set whether this view is a root of a keyboard navigation section.
-     *
-     * @param isSection If true, this view is a root of a section.
-     *
-     * @attr ref android.R.styleable#View_keyboardNavigationSection
-     */
-    public void setKeyboardNavigationSection(boolean isSection) {
-        if (isSection) {
-            mPrivateFlags3 |= PFLAG3_SECTION;
-        } else {
-            mPrivateFlags3 &= ~PFLAG3_SECTION;
-        }
-    }
-
-    final boolean isKeyboardNavigationGroupOfType(@KeyboardNavigationGroupType int groupType) {
-        switch (groupType) {
-            case KEYBOARD_NAVIGATION_GROUP_CLUSTER:
-                return isKeyboardNavigationCluster();
-            case KEYBOARD_NAVIGATION_GROUP_SECTION:
-                return isKeyboardNavigationSection();
-            default:
-                throw new IllegalArgumentException(
-                        "Unknown keyboard navigation group type: " + groupType);
-        }
-    }
-
-    /**
      * Returns whether this View should receive focus when the focus is restored for the view
      * hierarchy containing this view.
      * <p>
      * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
-     * window or serves as a target of cluster or section navigation.
+     * window or serves as a target of cluster navigation.
      *
      * @see #restoreDefaultFocus(int)
      *
@@ -9246,7 +9144,7 @@
      * hierarchy containing this view.
      * <p>
      * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
-     * window or serves as a target of cluster or section navigation.
+     * window or serves as a target of cluster navigation.
      *
      * @param isFocusedByDefault {@code true} to set this view as the default-focus view,
      *                           {@code false} otherwise.
@@ -9285,35 +9183,28 @@
     }
 
     /**
-     * Find the nearest keyboard navigation group in the specified direction. The group type can be
-     * either a cluster or a section.
-     * This does not actually give focus to that group.
+     * Find the nearest keyboard navigation cluster in the specified direction.
+     * This does not actually give focus to that cluster.
      *
-     * @param groupType Type of the keyboard navigation group
-     * @param currentGroup The starting point of the search. Null means the current group is not
-     *                     found yet
+     * @param currentCluster The starting point of the search. Null means the current cluster is not
+     *                       found yet
      * @param direction Direction to look
      *
-     * @return The nearest keyboard navigation group in the specified direction, or null if none
+     * @return The nearest keyboard navigation cluster in the specified direction, or null if none
      *         can be found
      */
-    public View keyboardNavigationGroupSearch(
-            @KeyboardNavigationGroupType int groupType, View currentGroup, int direction) {
-        if (isKeyboardNavigationGroupOfType(groupType)) {
-            currentGroup = this;
+    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+        if (isKeyboardNavigationCluster()) {
+            currentCluster = this;
         }
-        if (isRootNamespace()
-                || (groupType == KEYBOARD_NAVIGATION_GROUP_SECTION
-                && isKeyboardNavigationCluster())) {
+        if (isRootNamespace()) {
             // Root namespace means we should consider ourselves the top of the
             // tree for group searching; otherwise we could be group searching
             // into other tabs.  see LocalActivityManager and TabHost for more info.
-            // In addition, a cluster node works as a root for section searches.
-            return FocusFinder.getInstance().findNextKeyboardNavigationGroup(
-                    groupType, this, currentGroup, direction);
+            return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+                    this, currentCluster, direction);
         } else if (mParent != null) {
-            return mParent.keyboardNavigationGroupSearch(
-                    groupType, currentGroup, direction);
+            return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
         }
         return null;
     }
@@ -9441,19 +9332,16 @@
     }
 
     /**
-     * Adds any keyboard navigation group roots that are descendants of this view (possibly
-     * including this view if it is a group root itself) to views. The group type can be either a
-     * cluster or a section.
+     * Adds any keyboard navigation cluster roots that are descendants of this view (possibly
+     * including this view if it is a cluster root itself) to views.
      *
-     * @param groupType Type of the keyboard navigation group
-     * @param views Keyboard navigation group roots found so far
+     * @param views Keyboard navigation cluster roots found so far
      * @param direction Direction to look
      */
-    public void addKeyboardNavigationGroups(
-            @KeyboardNavigationGroupType int groupType,
+    public void addKeyboardNavigationClusters(
             @NonNull Collection<View> views,
             int direction) {
-        if (!(isKeyboardNavigationGroupOfType(groupType))) {
+        if (!(isKeyboardNavigationCluster())) {
             return;
         }
         views.add(this);
@@ -16642,6 +16530,12 @@
         // safe to free its copy of the display list as it knows that we will
         // push an updated DisplayList if we try to draw again
         resetDisplayList();
+        if (mOverlay != null) {
+            mOverlay.getOverlayView().destroyHardwareResources();
+        }
+        if (mGhostView != null) {
+            mGhostView.destroyHardwareResources();
+        }
     }
 
     /**
@@ -16812,11 +16706,9 @@
     }
 
     private void resetDisplayList() {
-        if (mRenderNode.isValid()) {
-            mRenderNode.discardDisplayList();
-        }
+        mRenderNode.discardDisplayList();
 
-        if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) {
+        if (mBackgroundRenderNode != null) {
             mBackgroundRenderNode.discardDisplayList();
         }
     }
@@ -22640,6 +22532,10 @@
         }
     }
 
+    private static boolean isViewIdGenerated(int id) {
+        return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0;
+    }
+
     /**
      * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions.
      * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and
@@ -24635,10 +24531,10 @@
      * menu). </li>
      * <li>On hover, after a brief delay since the pointer has stopped moving </li>
      *
-     * @param tooltip the tooltip text, or null if no tooltip is required
+     * @param tooltipText the tooltip text, or null if no tooltip is required
      */
-    public final void setTooltip(@Nullable CharSequence tooltip) {
-        if (TextUtils.isEmpty(tooltip)) {
+    public final void setTooltipText(@Nullable CharSequence tooltipText) {
+        if (TextUtils.isEmpty(tooltipText)) {
             setFlags(0, TOOLTIP);
             hideTooltip();
             mTooltipInfo = null;
@@ -24649,21 +24545,42 @@
                 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip;
                 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip;
             }
-            mTooltipInfo.mTooltip = tooltip;
+            mTooltipInfo.mTooltipText = tooltipText;
             if (mTooltipInfo.mTooltipPopup != null && mTooltipInfo.mTooltipPopup.isShowing()) {
-                mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltip);
+                mTooltipInfo.mTooltipPopup.updateContent(mTooltipInfo.mTooltipText);
             }
         }
     }
 
     /**
+     * To be removed once the support library has stopped using it.
+     *
+     * @deprecated use {@link #setTooltipText} instead
+     */
+    @Deprecated
+    public final void setTooltip(@Nullable CharSequence tooltipText) {
+        setTooltipText(tooltipText);
+    }
+
+    /**
      * Returns the view's tooltip text.
      *
      * @return the tooltip text
      */
     @Nullable
+    public final CharSequence getTooltipText() {
+        return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null;
+    }
+
+    /**
+     * To be removed once the support library has stopped using it.
+     *
+     * @deprecated use {@link #getTooltipText} instead
+     */
+    @Deprecated
+    @Nullable
     public final CharSequence getTooltip() {
-        return mTooltipInfo != null ? mTooltipInfo.mTooltip : null;
+        return getTooltipText();
     }
 
     private boolean showTooltip(int x, int y, boolean fromLongClick) {
@@ -24673,7 +24590,7 @@
         if ((mViewFlags & ENABLED_MASK) != ENABLED) {
             return false;
         }
-        final CharSequence tooltipText = getTooltip();
+        final CharSequence tooltipText = getTooltipText();
         if (TextUtils.isEmpty(tooltipText)) {
             return false;
         }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 6d2f850..0e753f3 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -83,6 +83,13 @@
     private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;
 
     /**
+     * Defines the duration in milliseconds a user needs to hold down the
+     * appropriate button to bring up the accessibility shortcut (first time) or enable it
+     * (once shortcut is configured).
+     */
+    private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;
+
+    /**
      * Defines the duration in milliseconds we will wait to see if a touch event
      * is a tap or a scroll. If the user does not move within this interval, it is
      * considered to be a tap.
@@ -785,6 +792,18 @@
     }
 
     /**
+     * The amount of time a user needs to press the relevant keys to activate the accessibility
+     * shortcut.
+     *
+     * @return how long a user needs to press the relevant keys to activate the accessibility
+     *   shortcut.
+     * @hide
+     */
+    public long getAccessibilityShortcutKeyTimeout() {
+        return A11Y_SHORTCUT_KEY_TIMEOUT;
+    }
+
+    /**
      * The amount of friction applied to scrolls and flings.
      *
      * @return A scalar dimensionless value representing the coefficient of
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b42a90..480741e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -915,13 +915,10 @@
      */
     @Override
     public View focusSearch(View focused, int direction) {
-        if (isRootNamespace()
-                || isKeyboardNavigationCluster()
-                && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD)) {
+        if (isRootNamespace()) {
             // root namespace means we should consider ourselves the top of the
             // tree for focus searching; otherwise we could be focus searching
             // into other tabs.  see LocalActivityManager and TabHost for more info.
-            // Cluster's root works same way for the forward and backward navigation.
             return FocusFinder.getInstance().findNextFocus(this, focused, direction);
         } else if (mParent != null) {
             return mParent.focusSearch(focused, direction);
@@ -1136,12 +1133,6 @@
 
     @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (isKeyboardNavigationCluster()
-                && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) && !hasFocus()) {
-            // A cluster cannot be focus-entered from outside using forward/backward navigation.
-            return;
-        }
-
         final int focusableCount = views.size();
 
         final int descendantFocusability = getDescendantFocusability();
@@ -1175,11 +1166,10 @@
     }
 
     @Override
-    public void addKeyboardNavigationGroups(
-            @KeyboardNavigationGroupType int groupType, Collection<View> views, int direction) {
+    public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
         final int focusableCount = views.size();
 
-        super.addKeyboardNavigationGroups(groupType, views, direction);
+        super.addKeyboardNavigationClusters(views, direction);
 
         if (focusableCount != views.size()) {
             // No need to look for groups inside a group.
@@ -1195,14 +1185,8 @@
 
         for (int i = 0; i < count; i++) {
             final View child = children[i];
-            if (groupType == KEYBOARD_NAVIGATION_GROUP_SECTION
-                    && child.isKeyboardNavigationCluster()) {
-                // When the current cluster is the default cluster, and we are searching for
-                // sections, ignore sections inside non-default clusters.
-                continue;
-            }
             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
-                child.addKeyboardNavigationGroups(groupType, views, direction);
+                child.addKeyboardNavigationClusters(views, direction);
             }
         }
     }
@@ -1788,15 +1772,15 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                final PointF point = getLocalPoint();
-                if (isTransformedTouchPointInView(x, y, child, point)) {
-                    final PointerIcon pointerIcon =
-                            dispatchResolvePointerIcon(event, pointerIndex, child);
-                    if (pointerIcon != null) {
-                        if (preorderedList != null) preorderedList.clear();
-                        return pointerIcon;
-                    }
-                    break;
+                if (!canViewReceivePointerEvents(child)
+                        || !isTransformedTouchPointInView(x, y, child, null)) {
+                    continue;
+                }
+                final PointerIcon pointerIcon =
+                        dispatchResolvePointerIcon(event, pointerIndex, child);
+                if (pointerIcon != null) {
+                    if (preorderedList != null) preorderedList.clear();
+                    return pointerIcon;
                 }
             }
             if (preorderedList != null) preorderedList.clear();
@@ -2091,11 +2075,12 @@
                                 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                         final View child =
                                 getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                        final PointF point = getLocalPoint();
-                        if (isTransformedTouchPointInView(x, y, child, point)) {
-                            if (dispatchTooltipHoverEvent(event, child)) {
-                                newTarget = child;
-                            }
+                        if (!canViewReceivePointerEvents(child)
+                                || !isTransformedTouchPointInView(x, y, child, null)) {
+                            continue;
+                        }
+                        if (dispatchTooltipHoverEvent(event, child)) {
+                            newTarget = child;
                             break;
                         }
                     }
@@ -3071,8 +3056,7 @@
         final View[] children = mChildren;
         for (int i = index; i != end; i += increment) {
             View child = children[i];
-            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                    && !child.isKeyboardNavigationCluster()) {
+            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
                 if (child.requestFocus(direction, previouslyFocusedRect)) {
                     return true;
                 }
@@ -3449,6 +3433,16 @@
         super.dispatchDetachedFromWindow();
     }
 
+    /** @hide */
+    @Override
+    protected void destroyHardwareResources() {
+        super.destroyHardwareResources();
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            getChildAt(i).destroyHardwareResources();
+        }
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index c9277ca..79b05cd 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.view.View.KeyboardNavigationGroupType;
 import android.view.accessibility.AccessibilityEvent;
 
 /**
@@ -148,20 +147,17 @@
     public View focusSearch(View v, int direction);
 
     /**
-     * Find the nearest keyboard navigation group in the specified direction. The group type can be
-     * either a cluster or a section.
-     * This does not actually give focus to that group.
+     * Find the nearest keyboard navigation cluster in the specified direction.
+     * This does not actually give focus to that cluster.
      *
-     * @param groupType Type of the keyboard navigation group
-     * @param currentGroup The starting point of the search. Null means the current group is not
-     *                     found yet
+     * @param currentCluster The starting point of the search. Null means the current cluster is not
+     *                       found yet
      * @param direction Direction to look
      *
-     * @return The nearest keyboard navigation group in the specified direction, or null if none
+     * @return The nearest keyboard navigation cluster in the specified direction, or null if none
      *         can be found
      */
-    View keyboardNavigationGroupSearch(
-            @KeyboardNavigationGroupType int groupType, View currentGroup, int direction);
+    View keyboardNavigationClusterSearch(View currentCluster, int direction);
 
     /**
      * Change the z order of the child so it's on top of all other children.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c0f2c37..3cbe82e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,8 +16,6 @@
 
 package android.view;
 
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_CLUSTER;
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_SECTION;
 import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
 import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -73,7 +71,6 @@
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
-import android.view.View.KeyboardNavigationGroupType;
 import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -4397,14 +4394,13 @@
             return false;
         }
 
-        private boolean performKeyboardGroupNavigation(
-                @KeyboardNavigationGroupType int groupType, int direction) {
+        private boolean performKeyboardGroupNavigation(int direction) {
             final View focused = mView.findFocus();
-            final View group = focused != null
-                    ? focused.keyboardNavigationGroupSearch(groupType, null, direction)
-                    : keyboardNavigationGroupSearch(groupType, null, direction);
+            final View cluster = focused != null
+                    ? focused.keyboardNavigationClusterSearch(null, direction)
+                    : keyboardNavigationClusterSearch(null, direction);
 
-            if (group != null && group.restoreDefaultFocus(View.FOCUS_DOWN)) {
+            if (cluster != null && cluster.restoreDefaultFocus(View.FOCUS_DOWN)) {
                 return true;
             }
 
@@ -4424,32 +4420,15 @@
             }
 
             int groupNavigationDirection = 0;
-            @KeyboardNavigationGroupType int groupType = 0;
 
             if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
                 final int character =
                         event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK);
                 if (character == '+') {
-                    groupType = KEYBOARD_NAVIGATION_GROUP_CLUSTER;
                     groupNavigationDirection = View.FOCUS_FORWARD;
                 }
 
                 if (character == '_') {
-                    groupType = KEYBOARD_NAVIGATION_GROUP_CLUSTER;
-                    groupNavigationDirection = View.FOCUS_BACKWARD;
-                }
-            }
-
-            if (event.getAction() == KeyEvent.ACTION_DOWN && event.isAltPressed()) {
-                final int character =
-                        event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_ALT_MASK);
-                if (character == '+') {
-                    groupType = KEYBOARD_NAVIGATION_GROUP_SECTION;
-                    groupNavigationDirection = View.FOCUS_FORWARD;
-                }
-
-                if (character == '_') {
-                    groupType = KEYBOARD_NAVIGATION_GROUP_SECTION;
                     groupNavigationDirection = View.FOCUS_BACKWARD;
                 }
             }
@@ -4479,7 +4458,7 @@
             // Handle automatic focus changes.
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 if (groupNavigationDirection != 0) {
-                    if (performKeyboardGroupNavigation(groupType, groupNavigationDirection)) {
+                    if (performKeyboardGroupNavigation(groupNavigationDirection)) {
                         return FINISH_HANDLED;
                     }
                 } else {
@@ -5910,11 +5889,10 @@
      * {@inheritDoc}
      */
     @Override
-    public View keyboardNavigationGroupSearch(
-            @KeyboardNavigationGroupType int groupType, View currentGroup, int direction) {
+    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
         checkThread();
-        return FocusFinder.getInstance().findNextKeyboardNavigationGroup(groupType,
-                mView, currentGroup, direction);
+        return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+                mView, currentCluster, direction);
     }
 
     public void debug() {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 3748134..bc4ae6d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -750,13 +750,14 @@
      * @param windowFlags Window layout flags.
      * @param overrideConfig override configuration to consider when generating
      *        context to for resources.
+     * @param displayId Id of the display to show the splash screen at.
      *
      * @return The starting surface.
      *
      */
     public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
-            int logo, int windowFlags, Configuration overrideConfig);
+            int logo, int windowFlags, Configuration overrideConfig, int displayId);
 
     /**
      * Prepare for a window being added to the window manager.  You can throw an
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 7f940f1..bfb8d83 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.NonNull;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
@@ -241,6 +242,8 @@
      * @hide
      */
     public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
+        // Constructor can't be chained because we can't create an instance of an inner class
+        // before calling another constructor.
         mHandler = new MyHandler(context.getMainLooper());
         mUserId = userId;
         synchronized (mLock) {
@@ -249,6 +252,23 @@
     }
 
     /**
+     * Create an instance.
+     *
+     * @param handler The handler to use
+     * @param service An interface to the backing service.
+     * @param userId User id under which to run.
+     *
+     * @hide
+     */
+    public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) {
+        mHandler = handler;
+        mUserId = userId;
+        synchronized (mLock) {
+            tryConnectToServiceLocked(service);
+        }
+    }
+
+    /**
      * @hide
      */
     public IAccessibilityManagerClient getClient() {
@@ -647,6 +667,30 @@
     }
 
     /**
+     * Find an installed service with the specified {@link ComponentName}.
+     *
+     * @param componentName The name to match to the service.
+     *
+     * @return The info corresponding to the installed service, or {@code null} if no such service
+     * is installed.
+     * @hide
+     */
+    public AccessibilityServiceInfo getInstalledServiceInfoWithComponentName(
+            ComponentName componentName) {
+        final List<AccessibilityServiceInfo> installedServiceInfos =
+                getInstalledAccessibilityServiceList();
+        if ((installedServiceInfos == null) || (componentName == null)) {
+            return null;
+        }
+        for (int i = 0; i < installedServiceInfos.size(); i++) {
+            if (componentName.equals(installedServiceInfos.get(i).getComponentName())) {
+                return installedServiceInfos.get(i);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Adds an accessibility interaction connection interface for a given window.
      * @param windowToken The window token to which a connection is added.
      * @param connection The connection.
@@ -693,6 +737,26 @@
         }
     }
 
+    /**
+     * Perform the accessibility shortcut if the caller has permission.
+     *
+     * @hide
+     */
+    public void performAccessibilityShortcut() {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return;
+            }
+        }
+        try {
+            service.performAccessibilityShortcut();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error performing accessibility shortcut. ", 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 f0bf7e5..56d45b0 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3998,8 +3998,10 @@
          * Obtains a pooled instance.
          *
          * @param type The type of the range.
-         * @param min The min value.
-         * @param max The max value.
+         * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
+         *            minimum.
+         * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
+         *            maximum.
          * @param current The current value.
          */
         public static RangeInfo obtain(int type, float min, float max, float current) {
@@ -4019,8 +4021,10 @@
          * Creates a new range.
          *
          * @param type The type of the range.
-         * @param min The min value.
-         * @param max The max value.
+         * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
+         *            minimum.
+         * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
+         *            maximum.
          * @param current The current value.
          */
         private RangeInfo(int type, float min, float max, float current) {
@@ -4044,18 +4048,18 @@
         }
 
         /**
-         * Gets the min value.
+         * Gets the minimum value.
          *
-         * @return The min value.
+         * @return The minimum value, or {@code Float.NEGATIVE_INFINITY} if no minimum exists.
          */
         public float getMin() {
             return mMin;
         }
 
         /**
-         * Gets the max value.
+         * Gets the maximum value.
          *
-         * @return The max value.
+         * @return The maximum value, or {@code Float.POSITIVE_INFINITY} if no maximum exists.
          */
         public float getMax() {
             return mMax;
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 2829744..ed77f68 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -60,7 +60,6 @@
 
     IBinder getWindowToken(int windowId, int userId);
 
-    void enableAccessibilityService(in ComponentName service, int userId);
-
-    void disableAccessibilityService(in ComponentName service, int userId);
+    // Requires WRITE_SECURE_SETTINGS
+    void performAccessibilityShortcut();
 }
diff --git a/core/java/android/view/textclassifier/EntityConfidence.java b/core/java/android/view/textclassifier/EntityConfidence.java
new file mode 100644
index 0000000..7aab71f
--- /dev/null
+++ b/core/java/android/view/textclassifier/EntityConfidence.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 android.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper object for setting and getting entity scores for classified text.
+ *
+ * @param <T> the entity type.
+ * @hide
+ */
+final class EntityConfidence<T> {
+
+    private final Map<T, Float> mEntityConfidence = new HashMap<>();
+
+    private final Comparator<T> mEntityComparator = (e1, e2) -> {
+        float score1 = mEntityConfidence.get(e1);
+        float score2 = mEntityConfidence.get(e2);
+        if (score1 > score2) {
+            return 1;
+        }
+        if (score1 < score2) {
+            return -1;
+        }
+        return 0;
+    };
+
+    EntityConfidence() {}
+
+    EntityConfidence(@NonNull EntityConfidence<T> source) {
+        Preconditions.checkNotNull(source);
+        mEntityConfidence.putAll(source.mEntityConfidence);
+    }
+
+    /**
+     * Sets an entity type for the classified text and assigns a confidence score.
+     *
+     * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+     *      0 implies the entity does not exist for the classified text.
+     *      Values greater than 1 are clamped to 1.
+     */
+    public void setEntityType(
+            @NonNull T type, @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+        Preconditions.checkNotNull(type);
+        if (confidenceScore > 0) {
+            mEntityConfidence.put(type, Math.min(1, confidenceScore));
+        } else {
+            mEntityConfidence.remove(type);
+        }
+    }
+
+    /**
+     * Returns an immutable list of entities found in the classified text ordered from
+     * high confidence to low confidence.
+     */
+    @NonNull
+    public List<T> getEntities() {
+        List<T> entities = new ArrayList<>(mEntityConfidence.size());
+        entities.addAll(mEntityConfidence.keySet());
+        entities.sort(mEntityComparator);
+        return Collections.unmodifiableList(entities);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(T entity) {
+        if (mEntityConfidence.containsKey(entity)) {
+            return mEntityConfidence.get(entity);
+        }
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return mEntityConfidence.toString();
+    }
+}
diff --git a/core/java/android/view/textclassifier/LinksInfo.java b/core/java/android/view/textclassifier/LinksInfo.java
new file mode 100644
index 0000000..3acbdc0
--- /dev/null
+++ b/core/java/android/view/textclassifier/LinksInfo.java
@@ -0,0 +1,41 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.NonNull;
+
+/**
+ * Link information that can be applied to text. See: {@link #apply(CharSequence)}.
+ * Typical implementations of this interface will annotate spannable text with e.g
+ * {@link android.text.style.ClickableSpan}s or other annotations.
+ */
+public interface LinksInfo {
+
+    /**
+     * @hide
+     */
+    LinksInfo NO_OP = text -> false;
+
+    /**
+     * Applies link annotations to the specified text.
+     * These annotations are not guaranteed to be applied. For example, the annotations may not be
+     * applied if the text has changed from what it was when the link spec was generated for it.
+     *
+     * @return Whether or not the link annotations were successfully applied.
+     */
+    boolean apply(@NonNull CharSequence text);
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
new file mode 100644
index 0000000..b5ab4bf
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -0,0 +1,53 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Interface to the text classification service.
+ *
+ * <p>You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService}.
+ */
+public final class TextClassificationManager {
+
+    /** @hide */
+    public TextClassificationManager(Context context) {}
+
+    /**
+     * Returns the default text classifier.
+     */
+    public TextClassifier getDefaultTextClassifier() {
+        return TextClassifier.NO_OP;
+    }
+
+    /**
+     * Returns information containing languages that were detected in the provided text.
+     * This is a blocking operation you should avoid calling it on the UI thread.
+     *
+     * @throws IllegalArgumentException if text is null
+     */
+    public List<TextLanguage> detectLanguages(@NonNull CharSequence text) {
+        // TODO: Implement
+        return Collections.emptyList();
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassificationResult.java b/core/java/android/view/textclassifier/TextClassificationResult.java
new file mode 100644
index 0000000..6af0efb
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassificationResult.java
@@ -0,0 +1,233 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.View.OnClickListener;
+import android.view.textclassifier.TextClassifier.EntityType;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Information for generating a widget to handle classified text.
+ */
+public final class TextClassificationResult {
+
+    /**
+     * @hide
+     */
+    static final TextClassificationResult EMPTY = new TextClassificationResult.Builder().build();
+
+    @NonNull private final String mText;
+    @Nullable private final Drawable mIcon;
+    @Nullable private final String mLabel;
+    @Nullable private final Intent mIntent;
+    @Nullable private final OnClickListener mOnClickListener;
+    @NonNull private final EntityConfidence<String> mEntityConfidence;
+    @NonNull private final List<String> mEntities;
+
+    private TextClassificationResult(
+            @NonNull String text,
+            Drawable icon,
+            String label,
+            Intent intent,
+            OnClickListener onClickListener,
+            @NonNull EntityConfidence<String> entityConfidence) {
+        mText = text;
+        mIcon = icon;
+        mLabel = label;
+        mIntent = intent;
+        mOnClickListener = onClickListener;
+        mEntityConfidence = new EntityConfidence<>(entityConfidence);
+        mEntities = mEntityConfidence.getEntities();
+    }
+
+    /**
+     * Gets the classified text.
+     */
+    @NonNull
+    public String getText() {
+        return mText;
+    }
+
+    /**
+     * Returns the number of entities found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getEntityCount() {
+        return mEntities.size();
+    }
+
+    /**
+     * Returns the entity at the specified index. Entities are ordered from high confidence
+     * to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getEntityCount() for the number of entities available.
+     */
+    @NonNull
+    public @EntityType String getEntity(int index) {
+        return mEntities.get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@EntityType String entity) {
+        return mEntityConfidence.getConfidenceScore(entity);
+    }
+
+    /**
+     * Returns an icon that may be rendered on a widget used to act on the classified text.
+     */
+    @Nullable
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Returns a label that may be rendered on a widget used to act on the classified text.
+     */
+    @Nullable
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+
+    /**
+     * Returns an intent that may be fired to act on the classified text.
+     */
+    @Nullable
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    /**
+     * Returns an OnClickListener that may be triggered to act on the classified text.
+     */
+    @Nullable
+    public OnClickListener getOnClickListener() {
+        return mOnClickListener;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("TextClassificationResult {"
+                        + "text=%s, entities=%s, label=%s, intent=%s}",
+                mText, mEntityConfidence, mLabel, mIntent);
+    }
+
+    /**
+     * Creates an OnClickListener that starts an activity with the specified intent.
+     *
+     * @throws IllegalArgumentException if context or intent is null
+     * @hide
+     */
+    @NonNull
+    public static OnClickListener createStartActivityOnClick(
+            @NonNull final Context context, @NonNull final Intent intent) {
+        Preconditions.checkArgument(context != null);
+        Preconditions.checkArgument(intent != null);
+        return v -> context.startActivity(intent);
+    }
+
+    /**
+     * Builder for building {@link TextClassificationResult}s.
+     */
+    public static final class Builder {
+
+        @NonNull private String mText;
+        @Nullable private Drawable mIcon;
+        @Nullable private String mLabel;
+        @Nullable private Intent mIntent;
+        @Nullable private OnClickListener mOnClickListener;
+        @NonNull private final EntityConfidence<String> mEntityConfidence =
+                new EntityConfidence<>();
+
+        /**
+         * Sets the classified text.
+         */
+        public Builder setText(@NonNull String text) {
+            mText = Preconditions.checkNotNull(text);
+            return this;
+        }
+
+        /**
+         * Sets an entity type for the classification result and assigns a confidence score.
+         *
+         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+         *      0 implies the entity does not exist for the classified text.
+         *      Values greater than 1 are clamped to 1.
+         */
+        public Builder setEntityType(
+                @NonNull @EntityType String type,
+                @FloatRange(from = 0.0, to = 1.0)float confidenceScore) {
+            mEntityConfidence.setEntityType(type, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Sets an icon that may be rendered on a widget used to act on the classified text.
+         */
+        public Builder setIcon(@Nullable Drawable icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Sets a label that may be rendered on a widget used to act on the classified text.
+         */
+        public Builder setLabel(@Nullable String label) {
+            mLabel = label;
+            return this;
+        }
+
+        /**
+         * Sets an intent that may be fired to act on the classified text.
+         */
+        public Builder setIntent(@Nullable Intent intent) {
+            mIntent = intent;
+            return this;
+        }
+
+        /**
+         * Sets an OnClickListener that may be triggered to act on the classified text.
+         */
+        public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
+            mOnClickListener = onClickListener;
+            return this;
+        }
+
+        /**
+         * Builds an returns a {@link TextClassificationResult}.
+         */
+        public TextClassificationResult build() {
+            return new TextClassificationResult(
+                    mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence);
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
new file mode 100644
index 0000000..b84e2ae
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -0,0 +1,114 @@
+/*
+ * 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.view.textclassifier;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface for providing text classification related features.
+ *
+ * <p>Unless otherwise stated, methods of this interface are blocking operations and you should
+ * avoid calling them on the UI thread.
+ */
+public interface TextClassifier {
+
+    String TYPE_OTHER = "other";
+    String TYPE_EMAIL = "email";
+    String TYPE_PHONE = "phone";
+    String TYPE_ADDRESS = "address";
+
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef({
+            TYPE_OTHER, TYPE_EMAIL, TYPE_PHONE, TYPE_ADDRESS
+    })
+    @interface EntityType {}
+
+    /**
+     * No-op TextClassifier.
+     * This may be used to turn off TextClassifier features.
+     */
+    TextClassifier NO_OP = new TextClassifier() {
+
+        @Override
+        public TextSelection suggestSelection(
+                CharSequence text, int selectionStartIndex, int selectionEndIndex) {
+            return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+        }
+
+        @Override
+        public TextClassificationResult getTextClassificationResult(
+                CharSequence text, int startIndex, int endIndex) {
+            return TextClassificationResult.EMPTY;
+        }
+
+        @Override
+        public LinksInfo getLinks(CharSequence text, int linkMask) {
+            return LinksInfo.NO_OP;
+        }
+    };
+
+    /**
+     * Returns suggested text selection indices, recognized types and their associated confidence
+     * scores. The selections are ordered from highest to lowest scoring.
+     *
+     * @param text text providing context for the selected text (which is specified
+     *      by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
+     * @param selectionStartIndex start index of the selected part of text
+     * @param selectionEndIndex end index of the selected part of text
+     *
+     * @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
+     *      selectionEndIndex is greater than text.length() or less than selectionStartIndex
+     */
+    @NonNull
+    TextSelection suggestSelection(
+            @NonNull CharSequence text,
+            @IntRange(from = 0) int selectionStartIndex,
+            @IntRange(from = 0) int selectionEndIndex);
+
+    /**
+     * Returns a {@link TextClassificationResult} object that can be used to generate a widget for
+     * handling the classified text.
+     *
+     * @param text text providing context for the text to classify (which is specified
+     *      by the sub sequence starting at startIndex and ending at endIndex)
+     * @param startIndex start index of the text to classify
+     * @param endIndex end index of the text to classify
+     *
+     * @throws IllegalArgumentException if text is null; startIndex is negative;
+     *      endIndex is greater than text.length() or less than startIndex
+     */
+    @NonNull
+    TextClassificationResult getTextClassificationResult(
+            @NonNull CharSequence text, int startIndex, int endIndex);
+
+    /**
+     * Returns a {@link LinksInfo} that may be applied to the text to annotate it with links
+     * information.
+     *
+     * @param text the text to generate annotations for
+     * @param linkMask See {@link android.text.util.Linkify} for a list of linkMasks that may be
+     *      specified. Subclasses of this interface may specify additional linkMasks
+     *
+     * @throws IllegalArgumentException if text is null
+     */
+    LinksInfo getLinks(@NonNull CharSequence text, int linkMask);
+}
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
new file mode 100644
index 0000000..d94d163
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextLanguage.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 android.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Specifies detected languages for a section of text indicated by a start and end index.
+ */
+public final class TextLanguage {
+
+    private final int mStartIndex;
+    private final int mEndIndex;
+    @NonNull private final EntityConfidence<Locale> mLanguageConfidence;
+    @NonNull private final List<Locale> mLanguages;
+
+    private TextLanguage(
+            int startIndex, int endIndex, @NonNull EntityConfidence<Locale> languageConfidence) {
+        mStartIndex = startIndex;
+        mEndIndex = endIndex;
+        mLanguageConfidence = new EntityConfidence<>(languageConfidence);
+        mLanguages = mLanguageConfidence.getEntities();
+    }
+
+    /**
+     * Returns the start index of the detected languages in the text provided to generate this
+     * object.
+     */
+    public int getStartIndex() {
+        return mStartIndex;
+    }
+
+    /**
+     * Returns the end index of the detected languages in the text provided to generate this object.
+     */
+    public int getEndIndex() {
+        return mEndIndex;
+    }
+
+    /**
+     * Returns the number of languages found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getLanguageCount() {
+        return mLanguages.size();
+    }
+
+    /**
+     * Returns the language locale at the specified index.
+     * Language locales are ordered from high confidence to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getLanguageCount() for the number of language locales available.
+     */
+    @NonNull
+    public Locale getLanguage(int index) {
+        return mLanguages.get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified language. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the language was
+     * not found for the classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@Nullable Locale language) {
+        return mLanguageConfidence.getConfidenceScore(language);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("TextLanguage {%d, %d, %s}",
+                mStartIndex, mEndIndex, mLanguageConfidence);
+    }
+
+    /**
+     * Builder to build {@link TextLanguage} objects.
+     */
+    public static final class Builder {
+
+        private final int mStartIndex;
+        private final int mEndIndex;
+        @NonNull private final EntityConfidence<Locale> mLanguageConfidence =
+                new EntityConfidence<>();
+
+        /**
+         * Creates a builder to build {@link TextLanguage} objects.
+         *
+         * @param startIndex the start index of the detected languages in the text provided
+         *      to generate the result
+         * @param endIndex the end index of the detected languages in the text provided
+         *      to generate the result. Must be greater than startIndex
+         */
+        public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) {
+            Preconditions.checkArgument(startIndex >= 0);
+            Preconditions.checkArgument(endIndex > startIndex);
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+        }
+
+        /**
+         * Sets a language locale with the associated confidence score.
+         */
+        public Builder setLanguage(
+                @NonNull Locale locale, @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+            mLanguageConfidence.setEntityType(locale, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Builds and returns a {@link TextLanguage}.
+         */
+        public TextLanguage build() {
+            return new TextLanguage(mStartIndex, mEndIndex, mLanguageConfidence);
+        }
+    }
+}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
new file mode 100644
index 0000000..3172c13
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextSelection.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 android.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.view.textclassifier.TextClassifier.EntityType;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Information about where text selection should be.
+ */
+public final class TextSelection {
+
+    private final int mStartIndex;
+    private final int mEndIndex;
+    @NonNull private final EntityConfidence<String> mEntityConfidence;
+    @NonNull private final List<String> mEntities;
+
+    private TextSelection(
+            int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence) {
+        mStartIndex = startIndex;
+        mEndIndex = endIndex;
+        mEntityConfidence = new EntityConfidence<>(entityConfidence);
+        mEntities = mEntityConfidence.getEntities();
+    }
+
+    /**
+     * Returns the start index of the text selection.
+     */
+    public int getSelectionStartIndex() {
+        return mStartIndex;
+    }
+
+    /**
+     * Returns the end index of the text selection.
+     */
+    public int getSelectionEndIndex() {
+        return mEndIndex;
+    }
+
+    /**
+     * Returns the number of entities found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getEntityCount() {
+        return mEntities.size();
+    }
+
+    /**
+     * Returns the entity at the specified index. Entities are ordered from high confidence
+     * to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getEntityCount() for the number of entities available.
+     */
+    @NonNull
+    public @EntityType String getEntity(int index) {
+        return mEntities.get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@EntityType String entity) {
+        return mEntityConfidence.getConfidenceScore(entity);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("TextSelection {%d, %d, %s}",
+                mStartIndex, mEndIndex, mEntityConfidence);
+    }
+
+    /**
+     * Builder used to build {@link TextSelection} objects.
+     */
+    public static final class Builder {
+
+        private final int mStartIndex;
+        private final int mEndIndex;
+        @NonNull private final EntityConfidence<String> mEntityConfidence =
+                new EntityConfidence<>();
+
+        /**
+         * Creates a builder used to build {@link TextSelection} objects.
+         *
+         * @param startIndex the start index of the text selection.
+         * @param endIndex the end index of the text selection. Must be greater than startIndex
+         */
+        public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) {
+            Preconditions.checkArgument(startIndex >= 0);
+            Preconditions.checkArgument(endIndex > startIndex);
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+        }
+
+        /**
+         * Sets an entity type for the classified text and assigns a confidence score.
+         *
+         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+         *      0 implies the entity does not exist for the classified text.
+         *      Values greater than 1 are clamped to 1.
+         */
+        public Builder setEntityType(
+                @NonNull @EntityType String type,
+                @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+            mEntityConfidence.setEntityType(type, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Builds and returns {@link TextSelection} object.
+         */
+        public TextSelection build() {
+            return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence);
+        }
+    }
+}
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index 894f080..dbca7ff 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -78,4 +78,14 @@
      * Enable or disable the WebView package fallback mechanism.
      */
     void enableFallbackLogic(boolean enable);
+
+    /**
+     * Used by Settings to determine whether multiprocess is enabled.
+     */
+    boolean isMultiProcessEnabled();
+
+    /**
+     * Used by Settings to enable/disable multiprocess.
+     */
+    void enableMultiProcess(boolean enable);
 }
diff --git a/core/java/android/webkit/RenderProcessGoneDetail.java b/core/java/android/webkit/RenderProcessGoneDetail.java
index 77d8596..1c79399 100644
--- a/core/java/android/webkit/RenderProcessGoneDetail.java
+++ b/core/java/android/webkit/RenderProcessGoneDetail.java
@@ -32,4 +32,15 @@
      *         system.
      **/
     public abstract boolean didCrash();
+
+    /**
+     * Returns the renderer priority that was set at the time that the
+     * renderer exited.  This may be greater than the priority that
+     * any individual {@link WebView} requested using
+     * {@link WebView#setRendererPriorityPolicy}.
+     *
+     * @return the priority of the renderer at exit.
+     **/
+    @WebView.RendererPriority
+    public abstract int rendererPriorityAtExit();
 }
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
new file mode 100644
index 0000000..404bcf4
--- /dev/null
+++ b/core/java/android/webkit/UserPackage.java
@@ -0,0 +1,94 @@
+/*
+ * 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.webkit;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class for storing a (user,PackageInfo) mapping.
+ * @hide
+ */
+public class UserPackage {
+    private final UserInfo mUserInfo;
+    private final PackageInfo mPackageInfo;
+
+    public UserPackage(UserInfo user, PackageInfo packageInfo) {
+        this.mUserInfo = user;
+        this.mPackageInfo = packageInfo;
+    }
+
+    /**
+     * Returns a list of (User,PackageInfo) pairs corresponding to the PackageInfos for all
+     * device users for the package named {@param packageName}.
+     */
+    public static List<UserPackage> getPackageInfosAllUsers(Context context,
+            String packageName, int packageFlags) {
+        List<UserInfo> users = getAllUsers(context);
+        List<UserPackage> userPackages = new ArrayList<UserPackage>(users.size());
+        for (UserInfo user : users) {
+            PackageInfo packageInfo = null;
+            try {
+                packageInfo = context.getPackageManager().getPackageInfoAsUser(
+                        packageName, packageFlags, user.id);
+            } catch (NameNotFoundException e) {
+            }
+            userPackages.add(new UserPackage(user, packageInfo));
+        }
+        return userPackages;
+    }
+
+    /**
+     * Returns whether the given package is enabled.
+     * This state can be changed by the user from Settings->Apps
+     */
+    public boolean isEnabledPackage() {
+        if (mPackageInfo == null) return false;
+        return mPackageInfo.applicationInfo.enabled;
+    }
+
+    /**
+     * Return true if the package is installed and not hidden
+     */
+    public boolean isInstalledPackage() {
+        if (mPackageInfo == null) return false;
+        return (((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
+            && ((mPackageInfo.applicationInfo.privateFlags
+                        & ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
+    }
+
+    public UserInfo getUserInfo() {
+        return mUserInfo;
+    }
+
+    public PackageInfo getPackageInfo() {
+        return mPackageInfo;
+    }
+
+
+    private static List<UserInfo> getAllUsers(Context context) {
+        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        return userManager.getUsers(false);
+    }
+
+}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f98c099..1e7cddf 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.Widget;
@@ -60,6 +61,8 @@
 
 import java.io.BufferedWriter;
 import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Map;
 
 /**
@@ -2151,6 +2154,94 @@
         return mProvider.findHierarchyView(className, hashCode);
     }
 
+    /** @hide */
+    @IntDef({
+        RENDERER_PRIORITY_WAIVED,
+        RENDERER_PRIORITY_BOUND,
+        RENDERER_PRIORITY_IMPORTANT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RendererPriority {}
+
+    /**
+     * The renderer associated with this WebView is bound with
+     * {@link Context#BIND_WAIVE_PRIORITY}. At this priority level
+     * {@link WebView} renderers will be strong targets for out of memory
+     * killing.
+     *
+     * Use with {@link #setRendererPriorityPolicy}.
+     */
+    public static final int RENDERER_PRIORITY_WAIVED = 0;
+    /**
+     * The renderer associated with this WebView is bound with
+     * the default priority for services.
+     *
+     * Use with {@link #setRendererPriorityPolicy}.
+     */
+    public static final int RENDERER_PRIORITY_BOUND = 1;
+    /**
+     * The renderer associated with this WebView is bound with
+     * {@link Context#BIND_IMPORTANT}.
+     *
+     * Use with {@link #setRendererPriorityPolicy}.
+     */
+    public static final int RENDERER_PRIORITY_IMPORTANT = 2;
+
+    /**
+     * Set the renderer priority policy for this {@link WebView}. The
+     * priority policy will be used to determine whether an out of
+     * process renderer should be considered to be a target for OOM
+     * killing.
+     *
+     * Because a renderer can be associated with more than one
+     * WebView, the final priority it is computed as the maximum of
+     * any attached WebViews. When a WebView is destroyed it will
+     * cease to be considerered when calculating the renderer
+     * priority. Once no WebViews remain associated with the renderer,
+     * the priority of the renderer will be reduced to
+     * {@link #RENDERER_PRIORITY_WAIVED}.
+     *
+     * The default policy is to set the priority to
+     * {@link #RENDERER_PRIORITY_IMPORTANT} regardless of visibility,
+     * and this should not be changed unless the caller also handles
+     * renderer crashes with
+     * {@link WebViewClient#onRenderProcessGone}. Any other setting
+     * will result in WebView renderers being killed by the system
+     * more aggressively than the application.
+     *
+     * @param rendererRequestedPriority the minimum priority at which
+     *        this WebView desires the renderer process to be bound.
+     * @param waivedWhenNotVisible if true, this flag specifies that
+     *        when this WebView is not visible, it will be treated as
+     *        if it had requested a priority of
+     *        {@link #RENDERER_PRIORITY_WAIVED}.
+     */
+    public void setRendererPriorityPolicy(
+            @RendererPriority int rendererRequestedPriority,
+            boolean waivedWhenNotVisible) {
+        mProvider.setRendererPriorityPolicy(rendererRequestedPriority, waivedWhenNotVisible);
+    }
+
+    /**
+     * Get the requested renderer priority for this WebView.
+     *
+     * @return the requested renderer priority policy.
+     */
+    @RendererPriority
+    public int getRendererRequestedPriority() {
+        return mProvider.getRendererRequestedPriority();
+    }
+
+    /**
+     * Return whether this WebView requests a priority of
+     * {@link #RENDERER_PRIORITY_WAIVED} when not visible.
+     *
+     * @return whether this WebView requests a priority of
+     * {@link #RENDERER_PRIORITY_WAIVED} when not visible.
+     */
+    public boolean getRendererPriorityWaivedWhenNotVisible() {
+        return mProvider.getRendererPriorityWaivedWhenNotVisible();
+    }
     //-------------------------------------------------------------------------
     // Interface for WebView providers
     //-------------------------------------------------------------------------
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 2cdff79..92d0d71 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -26,6 +26,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.SparseArray;
@@ -206,4 +207,15 @@
                     appInfo.getBaseResourcePath(), newAssetPath);
         }
     }
+
+    /**
+     * Returns whether WebView should run in multiprocess mode.
+     */
+    public boolean isMultiProcessEnabled() {
+        try {
+            return WebViewFactory.getUpdateService().isMultiProcessEnabled();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index dd1b0d2..ffc18b1 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -269,6 +269,12 @@
 
     public View findHierarchyView(String className, int hashCode);
 
+    public void setRendererPriorityPolicy(int rendererRequestedPriority, boolean waivedWhenNotVisible);
+
+    public int getRendererRequestedPriority();
+
+    public boolean getRendererPriorityWaivedWhenNotVisible();
+
     //-------------------------------------------------------------------------
     // Provider internal methods
     //-------------------------------------------------------------------------
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index af5c842..faf0379 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -42,6 +42,8 @@
  * <p>See the <a href="{@docRoot}guide/topics/ui/controls/text.html">Text Fields</a>
  * guide.</p>
  * <p>
+ * This widget does not support auto-sizing text.
+ * <p>
  * <b>XML attributes</b>
  * <p>
  * See {@link android.R.styleable#EditText EditText Attributes},
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 2703d6e..f7f9a81 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -60,8 +60,6 @@
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.StaticLayout;
-import android.text.TextClassification;
-import android.text.TextSelection;
 import android.text.TextUtils;
 import android.text.method.KeyListener;
 import android.text.method.MetaKeyKeyListener;
@@ -108,6 +106,8 @@
 import android.view.inputmethod.ExtractedTextRequest;
 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;
@@ -149,7 +149,7 @@
     private static final String UNDO_OWNER_TAG = "Editor";
 
     // Ordering constants used to place the Action Mode or context menu items in their menu.
-    // Reserve 1 for the app that the ASSIST logic suggests as the best app to handle the selection.
+    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;
@@ -238,6 +238,8 @@
     private boolean mPreserveSelection;
     private boolean mRestartActionModeOnNextRefresh;
 
+    private TextClassificationResult mTextClassificationResult;
+
     boolean mIsBeingLongClicked;
 
     private SuggestionsPopupWindow mSuggestionsPopupWindow;
@@ -1889,7 +1891,7 @@
             mInsertionPointCursorController.invalidateHandle();
         }
         if (mTextActionMode != null) {
-            mTextActionMode.invalidate();
+            invalidateActionMode(getTextClassifierInfo(false));
         }
     }
 
@@ -1982,12 +1984,12 @@
                 if (mRestartActionModeOnNextRefresh) {
                     // To avoid distraction, newly start action mode only when selection action
                     // mode is being restarted.
-                    startSelectionActionMode();
+                    startSelectionActionMode(getTextClassifierInfo(true));
                 }
             } else if (selectionController == null || !selectionController.isActive()) {
                 // Insertion action mode is active. Avoid dismissing the selection.
                 stopTextActionModeWithPreservingSelection();
-                startSelectionActionMode();
+                startSelectionActionMode(getTextClassifierInfo(true));
             } else {
                 mTextActionMode.invalidateContentRect();
             }
@@ -2031,7 +2033,8 @@
      *
      * @return true if the selection mode was actually started.
      */
-    boolean startSelectionActionMode() {
+    boolean startSelectionActionMode(@Nullable TextClassificationResult textClassificationResult) {
+        mTextClassificationResult = textClassificationResult;
         boolean selectionStarted = startSelectionActionModeInternal();
         if (selectionStarted) {
             getSelectionController().show();
@@ -2040,6 +2043,40 @@
         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);
+    }
+
     /**
      * If the TextView allows text selection, selects the current word when no existing selection
      * was available and starts a drag.
@@ -2086,7 +2123,7 @@
         }
         if (mTextActionMode != null) {
             // Text action mode is already started
-            mTextActionMode.invalidate();
+            invalidateActionMode(getTextClassifierInfo(false));
             return false;
         }
 
@@ -2480,7 +2517,7 @@
     }
 
     void onDrop(DragEvent event) {
-        StringBuilder content = new StringBuilder("");
+        SpannableStringBuilder content = new SpannableStringBuilder();
 
         final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event);
         if (permissions != null) {
@@ -3744,8 +3781,7 @@
         private final Path mSelectionPath = new Path();
         private final RectF mSelectionBounds = new RectF();
         private final boolean mHasSelection;
-
-        private int mHandleHeight;
+        private final int mHandleHeight;
 
         public TextActionModeCallback(boolean hasSelection) {
             mHasSelection = hasSelection;
@@ -3765,18 +3801,19 @@
                 if (insertionController != null) {
                     insertionController.getHandle();
                     mHandleHeight = mSelectHandleCenter.getMinimumHeight();
+                } else {
+                    mHandleHeight = 0;
                 }
             }
         }
 
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
-            TextClassification textClassification = updateSelectionWithTextAssistant();
-
             mode.setTitle(null);
             mode.setSubtitle(null);
             mode.setTitleOptionalHint(true);
-            populateMenuWithItems(menu, textClassification);
+            populateMenuWithItems(menu);
+            updateAssistMenuItem(menu, mTextClassificationResult);
 
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
@@ -3802,30 +3839,13 @@
             }
         }
 
-        private TextClassification updateSelectionWithTextAssistant() {
-            // Trim the text so that only text necessary to provide context of the selected text is
-            // sent to the assistant.
-            CharSequence trimmedText = mTextView.getText();
-            int textLength = mTextView.getText().length();
-            int trimStartIndex = 0;
-            int startIndex = mTextView.getSelectionStart() - trimStartIndex;
-            int endIndex = mTextView.getSelectionEnd() - trimStartIndex;
-            TextSelection textSelection = mTextView.getTextAssistant()
-                    .suggestSelection(trimmedText, startIndex, endIndex);
-            Selection.setSelection(
-                    (Spannable) mTextView.getText(),
-                    Math.max(0, textSelection.getSelectionStartIndex() + trimStartIndex),
-                    Math.min(textLength, textSelection.getSelectionEndIndex() + trimStartIndex));
-            return textSelection.getTextClassification();
-        }
-
         private Callback getCustomCallback() {
             return mHasSelection
                     ? mCustomSelectionActionModeCallback
                     : mCustomInsertionActionModeCallback;
         }
 
-        private void populateMenuWithItems(Menu menu, TextClassification textClassification) {
+        private void populateMenuWithItems(Menu menu) {
             if (mTextView.canCut()) {
                 menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT,
                         com.android.internal.R.string.cut)
@@ -3855,13 +3875,13 @@
 
             updateSelectAllItem(menu);
             updateReplaceItem(menu);
-            updateAssistMenuItem(menu, textClassification);
         }
 
         @Override
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
             updateSelectAllItem(menu);
             updateReplaceItem(menu);
+            updateAssistMenuItem(menu, mTextClassificationResult);
 
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
@@ -3894,10 +3914,16 @@
             }
         }
 
-        private void updateAssistMenuItem(Menu menu, TextClassification textClassification) {
-            // TODO: Find the best app available to handle the selected text based on information in
-            // the TextClassification object.
-            // Add app icon + intent to trigger app to the menu.
+        private void updateAssistMenuItem(
+                Menu menu, TextClassificationResult textClassificationResult) {
+            menu.removeItem(TextView.ID_ASSIST);
+            if (textClassificationResult != null
+                    && textClassificationResult.getIcon() != null
+                    && textClassificationResult.getOnClickListener() != null) {
+                menu.add(Menu.NONE, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, null)
+                        .setIcon(textClassificationResult.getIcon())
+                        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+            }
         }
 
         @Override
@@ -3909,6 +3935,10 @@
             if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
                 return true;
             }
+            if (TextView.ID_ASSIST == item.getItemId() && mTextClassificationResult != null) {
+                mTextClassificationResult.getOnClickListener().onClick(mTextView);
+                stopTextActionMode();
+            }
             return mTextView.onTextContextMenuItem(item.getItemId());
         }
 
@@ -3916,6 +3946,7 @@
         public void onDestroyActionMode(ActionMode mode) {
             // Clear mTextActionMode not to recursively destroy action mode by clearing selection.
             mTextActionMode = null;
+            mTextClassificationResult = null;
             Callback customCallback = getCustomCallback();
             if (customCallback != null) {
                 customCallback.onDestroyActionMode(mode);
@@ -4733,7 +4764,7 @@
             }
             positionAtCursorOffset(offset, false);
             if (mTextActionMode != null) {
-                mTextActionMode.invalidate();
+                invalidateActionMode(getTextClassifierInfo(false));
             }
         }
 
@@ -4817,7 +4848,7 @@
             }
             updateDrawable();
             if (mTextActionMode != null) {
-                mTextActionMode.invalidate();
+                invalidateActionMode(getTextClassifierInfo(false));
             }
         }
 
@@ -5465,7 +5496,8 @@
                     resetDragAcceleratorState();
 
                     if (mTextView.hasSelection()) {
-                        startSelectionActionMode();
+                        // TODO: Do not invoke the text assistant if this was a drag selection.
+                        startSelectionActionMode(getTextClassifierInfo(true));
                     }
                     break;
             }
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index eb27533..59bbc3b 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.MenuRes;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.view.Gravity;
 import android.view.Menu;
@@ -281,4 +282,19 @@
          */
         void onDismiss(PopupMenu menu);
     }
+
+    /**
+     * Returns the {@link ListView} representing the list of menu items in the currently showing
+     * menu.
+     *
+     * @return The view representing the list of menu items.
+     * @hide
+     */
+    @TestApi
+    public ListView getMenuListView() {
+        if (!mPopup.isShowing()) {
+            return null;
+        }
+        return mPopup.getPopup().getListView();
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 345896a..2f303cd 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -22,6 +22,7 @@
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.FloatRange;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
@@ -76,8 +77,6 @@
 import android.text.Spanned;
 import android.text.SpannedString;
 import android.text.StaticLayout;
-import android.text.TextAssistant;
-import android.text.TextClassificationManager;
 import android.text.TextDirectionHeuristic;
 import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
@@ -145,6 +144,8 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.textclassifier.TextClassificationManager;
+import android.view.textclassifier.TextClassifier;
 import android.view.textservice.SpellCheckerSubtype;
 import android.view.textservice.TextServicesManager;
 import android.widget.RemoteViews.RemoteView;
@@ -158,6 +159,8 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Locale;
@@ -252,6 +255,10 @@
  * @attr ref android.R.styleable#TextView_fontFeatureSettings
  * @attr ref android.R.styleable#TextView_breakStrategy
  * @attr ref android.R.styleable#TextView_hyphenationFrequency
+ * @attr ref android.R.styleable#TextView_autoSizeText
+ * @attr ref android.R.styleable#TextView_autoSizeMinTextSize
+ * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
+ * @attr ref android.R.styleable#TextView_autoSizeStepGranularity
  */
 @RemoteView
 public class TextView extends View implements ViewTreeObserver.OnPreDrawListener {
@@ -345,6 +352,8 @@
     private boolean mPreDrawRegistered;
     private boolean mPreDrawListenerDetached;
 
+    private TextClassifier mTextClassifier;
+
     // A flag to prevent repeated movements from escaping the enclosing text view. The idea here is
     // that if a user is holding down a movement key to traverse text, we shouldn't also traverse
     // the view hierarchy. On the other hand, if the user is using the movement key to traverse
@@ -670,17 +679,31 @@
      */
     private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN;
 
-    // The TextView does not auto-size text.
-    public static final int AUTO_SIZE_TYPE_NONE = 0;
+    // The TextView does not auto-size text (default).
+    public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0;
     // The TextView performs uniform horizontal and vertical text size scaling to fit within the
     // container.
-    public static final int AUTO_SIZE_TYPE_XY = 1;
-    // Auto-size type.
-    private int mAutoSizeType = AUTO_SIZE_TYPE_NONE;
-    // Specify if auto-size is needed.
-    private boolean mNeedsAutoSize = false;
+    public static final int AUTO_SIZE_TEXT_TYPE_XY = 1;
+    /** @hide */
+    @IntDef({AUTO_SIZE_TEXT_TYPE_NONE, AUTO_SIZE_TEXT_TYPE_XY})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AutoSizeTextType {}
+    // Default minimum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMinTextSize}.
+    private static final int DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP = 12;
+    // Default maximum size for auto-sizing text in scaled pixels. {@see #setAutoSizeMaxTextSize}.
+    private static final int DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP = 112;
     // Default value for the step size in pixels.
     private static final int DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX = 1;
+    // Auto-size text type.
+    private int mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE;
+    // Specify if auto-size text is needed.
+    private boolean mNeedsAutoSizeText = false;
+    // Step size for auto-sizing in pixels.
+    private int mAutoSizeStepGranularityInPx = 0;
+    // Minimum text size for auto-sizing in pixels.
+    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;
 
@@ -887,13 +910,6 @@
         CharSequence hint = null;
         boolean password = false;
         int inputType = EditorInfo.TYPE_NULL;
-        int autoSizeStepGranularityInPx = DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX;
-        int autoSizeMinTextSize = (int) TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());
-        int autoSizeMaxTextSize = (int) TypedValue.applyDimension(
-                TypedValue.COMPLEX_UNIT_SP, 112, getResources().getDisplayMetrics());
-
-
         a = theme.obtainStyledAttributes(
                     attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
 
@@ -1249,20 +1265,19 @@
                     break;
 
                 case com.android.internal.R.styleable.TextView_autoSizeText:
-                    mAutoSizeType = a.getInt(attr, AUTO_SIZE_TYPE_NONE);
+                    mAutoSizeTextType = a.getInt(attr, AUTO_SIZE_TEXT_TYPE_NONE);
                     break;
 
                 case com.android.internal.R.styleable.TextView_autoSizeStepGranularity:
-                    autoSizeStepGranularityInPx = a.getDimensionPixelSize(
-                            attr, DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX);
+                    mAutoSizeStepGranularityInPx = a.getDimensionPixelSize(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextView_autoSizeMinTextSize:
-                    autoSizeMinTextSize = a.getDimensionPixelSize(attr, autoSizeMinTextSize);
+                    mAutoSizeMinTextSizeInPx = a.getDimensionPixelSize(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextView_autoSizeMaxTextSize:
-                    autoSizeMaxTextSize = a.getDimensionPixelSize(attr, autoSizeMaxTextSize);
+                    mAutoSizeMaxTextSizeInPx = a.getDimensionPixelSize(attr, 0);
                     break;
             }
         }
@@ -1542,39 +1557,204 @@
             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
         }
 
-        // Setup auto-size.
+        setupAutoSizeTextXY();
+    }
+
+    /**
+     * Specify whether this widget should automatically scale the text to try to perfectly fit
+     * within the layout bounds by taking into account the auto-size configuration.
+     *
+     * @param autoSizeTextType the type of auto-size. Must be one of
+     *        {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
+     *        {@link TextView#AUTO_SIZE_TEXT_TYPE_XY}
+     *
+     * @attr ref android.R.styleable#TextView_autoSizeText
+     *
+     * @see #getAutoSizeTextType()
+     */
+    public void setAutoSizeTextType(@AutoSizeTextType int autoSizeTextType) {
         if (supportsAutoSizeText()) {
-            switch (mAutoSizeType) {
-                case AUTO_SIZE_TYPE_NONE:
-                    // Nothing to do.
+            switch (autoSizeTextType) {
+                case AUTO_SIZE_TEXT_TYPE_NONE:
+                    if (mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_NONE) {
+                        // Clear all auto-size configuration
+                        mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE;
+                        mAutoSizeMinTextSizeInPx = 0;
+                        mAutoSizeMaxTextSizeInPx = 0;
+                        mAutoSizeStepGranularityInPx = 0;
+                        mAutoSizeTextSizesInPx = null;
+                        mNeedsAutoSizeText = false;
+                    }
                     break;
-                case AUTO_SIZE_TYPE_XY:
-                    if (autoSizeMaxTextSize <= autoSizeMinTextSize) {
-                        throw new IllegalStateException("Maximum text size is less then minimum "
-                                + "text size");
+                case AUTO_SIZE_TEXT_TYPE_XY:
+                    if (mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_XY) {
+                        mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_XY;
+                        setupAutoSizeTextXY();
                     }
-
-                    if (autoSizeStepGranularityInPx <= 0) {
-                        throw new IllegalStateException("Unexpected zero or negative value for auto"
-                                + " size step granularity in pixels");
-                    }
-
-                    final int autoSizeValuesLength = (autoSizeMaxTextSize - autoSizeMinTextSize)
-                            / autoSizeStepGranularityInPx;
-                    mAutoSizeTextSizesInPx = new int[autoSizeValuesLength];
-                    int sizeToAdd = autoSizeMinTextSize;
-                    for (int i = 0; i < autoSizeValuesLength; i++) {
-                        mAutoSizeTextSizesInPx[i] = sizeToAdd;
-                        sizeToAdd += autoSizeStepGranularityInPx;
-                    }
-
-                    mNeedsAutoSize = true;
                     break;
                 default:
                     throw new IllegalArgumentException(
-                            "Unknown autoSizeText type: " + mAutoSizeType);
+                            "Unknown auto-size text type: " + autoSizeTextType);
+            }
+        }
+    }
+
+    /**
+     * Returns the type of auto-size set for this widget.
+     *
+     * @return an {@code int} corresponding to one of the auto-size types:
+     *         {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
+     *         {@link TextView#AUTO_SIZE_TEXT_TYPE_XY}
+     *
+     * @attr ref android.R.styleable#TextView_autoSizeText
+     *
+     * @see #setAutoSizeTextType(int)
+     */
+    @AutoSizeTextType
+    public int getAutoSizeTextType() {
+        return mAutoSizeTextType;
+    }
+
+    /**
+     * Sets the auto-size step granularity. It is used in conjunction with auto-size minimum
+     * and maximum text size in order to build the set of text sizes the system uses to choose
+     * from when auto-sizing.
+     *
+     * @param unit the desired dimension unit. See {@link TypedValue} for the possible
+     *             dimension units
+     * @param size the desired size in the given units
+     *
+     * @attr ref android.R.styleable#TextView_autoSizeStepGranularity
+     *
+     * @see #getAutoSizeStepGranularity()
+     * @see #setAutoSizeMinTextSize(int, float)
+     * @see #setAutoSizeMaxTextSize(int, float)
+     */
+    public void setAutoSizeStepGranularity(int unit, float size) {
+        if (supportsAutoSizeText()) {
+            mAutoSizeStepGranularityInPx = (int) TypedValue.applyDimension(
+                    unit, size, getResources().getDisplayMetrics());
+            setupAutoSizeTextXY();
+        }
+    }
+
+    /**
+     * @return the current auto-size step granularity in pixels.
+     *
+     * @see #setAutoSizeStepGranularity(int, float)
+     */
+    public int getAutoSizeStepGranularity() {
+        return mAutoSizeStepGranularityInPx;
+    }
+
+    /**
+     * Sets the minimum text size to be used in conjunction with auto-size maximum text size and
+     * auto-size step granularity in order to build the set of text sizes the system uses to choose
+     * from when auto-sizing.
+     *
+     * @param unit the desired dimension unit. See {@link TypedValue} for the possible
+     *             dimension units
+     * @param size the desired size in the given units
+     *
+     * @attr ref android.R.styleable#TextView_autoSizeMinTextSize
+     *
+     * @see #getAutoSizeMinTextSize()
+     * @see #setAutoSizeMaxTextSize(int, float)
+     * @see #setAutoSizeStepGranularity(int, float)
+     */
+    public void setAutoSizeMinTextSize(int unit, float size) {
+        if (supportsAutoSizeText()) {
+            mAutoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
+                    unit, size, getResources().getDisplayMetrics());
+            setupAutoSizeTextXY();
+        }
+    }
+
+    /**
+     * @return the current auto-size minimum text size in pixels (the default is 12sp). Note that
+     *         if auto-size has not been configured this function returns {@code 0}.
+     *
+     * @see #setAutoSizeMinTextSize(int, float)
+     */
+    public int getAutoSizeMinTextSize() {
+        return mAutoSizeMinTextSizeInPx;
+    }
+
+    /**
+     * Sets the maximum text size to be used in conjunction with auto-size minimum text size and
+     * auto-size step granularity in order to build the set of text sizes the system uses to choose
+     * from when auto-sizing.
+     *
+     * @param unit the desired dimension unit. See {@link TypedValue} for the possible
+     *             dimension units
+     * @param size the desired size in the given units
+     *
+     * @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
+     *
+     * @see #getAutoSizeMaxTextSize()
+     * @see #setAutoSizeMinTextSize(int, float)
+     * @see #setAutoSizeStepGranularity(int, float)
+     */
+    public void setAutoSizeMaxTextSize(int unit, float size) {
+        if (supportsAutoSizeText()) {
+            mAutoSizeMaxTextSizeInPx = (int) TypedValue.applyDimension(
+                    unit, size, getResources().getDisplayMetrics());
+            setupAutoSizeTextXY();
+        }
+    }
+
+    /**
+     * @return the current auto-size maximum text size in pixels (the default is 112sp). Note that
+     *         if auto-size has not been configured this function returns {@code 0}.
+     *
+     * @see #setAutoSizeMaxTextSize(int, float)
+     */
+    public int getAutoSizeMaxTextSize() {
+        return mAutoSizeMaxTextSizeInPx;
+    }
+
+    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());
             }
 
+            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;
+            }
+
+            // 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;
+            }
+
+            mNeedsAutoSizeText = true;
+            autoSizeText();
         }
     }
 
@@ -3030,9 +3210,6 @@
 
     /**
      * @return the size (in pixels) of the default text size in this TextView.
-     *
-     * <p>Note: if this TextView has mAutoSizeType set to {@link TextView#AUTO_SIZE_TYPE_XY} than
-     * this function returns the maximum text size for auto-sizing.
      */
     @ViewDebug.ExportedProperty(category = "text")
     public float getTextSize() {
@@ -3077,7 +3254,7 @@
     }
 
     /**
-     * Set the default text size to a given unit and value.  See {@link
+     * Set the default text size to a given unit and value. See {@link
      * TypedValue} for the possible dimension units.
      *
      * <p>Note: if this TextView has the auto-size feature enabled than this function is no-op.
@@ -3113,7 +3290,7 @@
 
             if (mLayout != null) {
                 // Do not auto-size right after setting the text size.
-                mNeedsAutoSize = false;
+                mNeedsAutoSizeText = false;
                 nullLayouts();
                 requestLayout();
                 invalidate();
@@ -3257,20 +3434,6 @@
     }
 
     /**
-     * Returns the font variation settings.
-     *
-     * @return the currently set font variation settings.  Returns null if no variation is
-     * specified.
-     *
-     * @see #setFontVariationSettings(String)
-     * @see Paint#setFontVariationSettings(String) Paint.setFontVariationSettings(String)
-     */
-    @Nullable
-    public String getFontVariationSettings() {
-        return mTextPaint.getFontVariationSettings();
-    }
-
-    /**
      * Sets the break strategy for breaking paragraphs into lines. The default value for
      * TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for
      * EditText is {@link Layout#BREAK_STRATEGY_SIMPLE}, the latter to avoid the
@@ -3377,41 +3540,6 @@
 
 
     /**
-     * Sets TrueType or OpenType font variation settings. The settings string is constructed from
-     * multiple pairs of axis tag and style values. The axis tag must contain four ASCII characters
-     * and must be wrapped with single quotes (U+0027) or double quotes (U+0022). Axis strings that
-     * are longer or shorter than four characters, or contain characters outside of U+0020..U+007E
-     * are invalid. If a specified axis name is not defined in the font, the settings will be
-     * ignored.
-     *
-     * <pre>
-     *   textView.setFontVariationSettings("'wdth' 1.0");
-     *   textView.setFontVariationSettings("'AX  ' 1.8, 'FB  ' 2.0");
-     * </pre>
-     *
-     * @param fontVariationSettings font variation settings. You can pass null or empty string as
-     *                              no variation settings.
-     *
-     * @see #getFontVariationSettings()
-     * @see Paint#getFontVariationSettings() Paint.getFontVariationSettings()
-     */
-    public void setFontVariationSettings(@Nullable String fontVariationSettings) {
-        final String existingSettings = mTextPaint.getFontVariationSettings();
-        if (fontVariationSettings == existingSettings
-                || (fontVariationSettings != null
-                        && fontVariationSettings.equals(existingSettings))) {
-            return;
-        }
-        mTextPaint.setFontVariationSettings(fontVariationSettings);
-
-        if (mLayout != null) {
-            nullLayouts();
-            requestLayout();
-            invalidate();
-        }
-    }
-
-    /**
      * Sets the text color for all the states (normal, selected,
      * focused) to be this color.
      *
@@ -7612,13 +7740,13 @@
         }
 
         if (isAutoSizeEnabled()) {
-            if (mNeedsAutoSize) {
+            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.
-            mNeedsAutoSize = true;
+            mNeedsAutoSizeText = true;
         }
 
         setMeasuredDimension(width, height);
@@ -7740,14 +7868,25 @@
             desired = Math.max(desired, dr.mDrawableHeightRight);
         }
 
-        desired += getCompoundPaddingTop() + getCompoundPaddingBottom();
+        int linecount = layout.getLineCount();
+        final int padding = getCompoundPaddingTop() + getCompoundPaddingBottom();
+        desired += padding;
 
         if (mMaxMode != LINES) {
             desired = Math.min(desired, mMaximum);
+        } else if (cap && linecount > mMaximum && layout instanceof DynamicLayout) {
+            desired = layout.getLineTop(mMaximum);
+
+            if (dr != null) {
+                desired = Math.max(desired, dr.mDrawableHeightLeft);
+                desired = Math.max(desired, dr.mDrawableHeightRight);
+            }
+
+            desired += padding;
+            linecount = mMaximum;
         }
 
         if (mMinMode == LINES) {
-            int linecount = layout.getLineCount();
             if (linecount < mMinimum) {
                 desired += getLineHeight() * (mMinimum - linecount);
             }
@@ -9366,7 +9505,7 @@
      * auto-size.
      */
     private boolean isAutoSizeEnabled() {
-        return supportsAutoSizeText() && mAutoSizeType != AUTO_SIZE_TYPE_NONE;
+        return supportsAutoSizeText() && mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_NONE;
     }
 
     /**
@@ -9753,7 +9892,7 @@
                         Selection.setSelection((Spannable) text, start, end);
                         // Make sure selection mode is engaged.
                         if (mEditor != null) {
-                            mEditor.startSelectionActionMode();
+                            mEditor.startSelectionActionMode(null);
                         }
                         return true;
                     }
@@ -9897,6 +10036,7 @@
     static final int ID_SHARE = android.R.id.shareText;
     static final int ID_PASTE_AS_PLAIN_TEXT = android.R.id.pasteAsPlainText;
     static final int ID_REPLACE = android.R.id.replaceText;
+    static final int ID_ASSIST = android.R.id.textAssist;
 
     /**
      * Called when a context menu option for the text view is selected.  Currently
@@ -10121,33 +10261,30 @@
         return mEditor == null ? null : mEditor.mCustomInsertionActionModeCallback;
     }
 
-    private TextAssistant mTextAssistant;
-
     /**
-     * Sets the {@link TextAssistant} for this TextView.
-     * If null, this TextView uses the default TextAssistant which comes from the Activity.
+     * Sets the {@link TextClassifier} for this TextView.
      */
-    public void setTextAssistant(TextAssistant textAssistant) {
-        mTextAssistant = textAssistant;
+    public void setTextClassifier(@Nullable TextClassifier textClassifier) {
+        mTextClassifier = textClassifier;
     }
 
     /**
-     * Returns the {@link TextAssistant} used by this TextView.
-     * If no TextAssistant is set, it'll use the one from this TextView's {@link Activity} or
-     * {@link Context}. If no TextAssistant is found, it'll use a no-op TextAssistant.
+     * Returns the {@link TextClassifier} used by this TextView.
+     * If no TextClassifier has been set, this TextView uses the default set by the
+     * {@link TextClassificationManager}.
      */
-    public TextAssistant getTextAssistant() {
-        if (mTextAssistant != null) {
-            return mTextAssistant;
+    @NonNull
+    public TextClassifier getTextClassifier() {
+        if (mTextClassifier == null) {
+            TextClassificationManager tcm =
+                    mContext.getSystemService(TextClassificationManager.class);
+            if (tcm != null) {
+                mTextClassifier = tcm.getDefaultTextClassifier();
+            } else {
+                mTextClassifier = TextClassifier.NO_OP;
+            }
         }
-        if (mContext instanceof Activity) {
-            mTextAssistant = ((Activity) mContext).getTextAssistant();
-        } else {
-            // The context of this TextView should be an Activity. If it is not and no
-            // text assistant has been set, return the TextClassificationManager.
-            mTextAssistant = mContext.getSystemService(TextClassificationManager.class);
-        }
-        return  mTextAssistant;
+        return mTextClassifier;
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index d734d17..ab1d9b9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -749,10 +749,7 @@
                     }
                 } else {
                     try {
-                        AppGlobals.getPackageManager().setLastChosenActivity(intent,
-                                intent.resolveType(getContentResolver()),
-                                PackageManager.MATCH_DEFAULT_ONLY,
-                                filter, bestMatch, intent.getComponent());
+                        mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch);
                     } catch (RemoteException re) {
                         Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
                     }
@@ -1312,10 +1309,7 @@
         protected boolean rebuildList() {
             List<ResolvedComponentInfo> currentResolveList = null;
             try {
-                final Intent primaryIntent = getTargetIntent();
-                mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
-                        primaryIntent, primaryIntent.resolveTypeIfNeeded(getContentResolver()),
-                        PackageManager.MATCH_DEFAULT_ONLY);
+                mLastChosen = mResolverListController.getLastChosen();
             } catch (RemoteException re) {
                 Log.d(TAG, "Error calling getLastChosenActivity\n" + re);
             }
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index d9ab47e..096fcb8 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -343,53 +343,42 @@
     class LogisticRegressionAppRanker {
         private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params";
         private static final String BIAS_PREF_KEY = "bias";
-        private static final float LEARNING_RATE = 0.02f;
-        private static final float REGULARIZER_PARAM = 0.1f;
+        private static final String VERSION_PREF_KEY = "version";
+
+        // parameters for a pre-trained model, to initialize the app ranker. When updating the
+        // pre-trained model, please update these params, as well as initModel().
+        private static final int CURRENT_VERSION = 1;
+        private static final float LEARNING_RATE = 0.0001f;
+        private static final float REGULARIZER_PARAM = 0.0001f;
+
         private SharedPreferences mParamSharedPref;
         private ArrayMap<String, Float> mFeatureWeights;
         private float mBias;
 
         public LogisticRegressionAppRanker(Context context) {
             mParamSharedPref = getParamSharedPref(context);
+            initModel();
         }
 
         public float predict(ArrayMap<String, Float> target) {
-            if (target == null || mParamSharedPref == null) {
+            if (target == null) {
                 return 0.0f;
             }
             final int featureSize = target.size();
-            if (featureSize == 0) {
-                return 0.0f;
-            }
             float sum = 0.0f;
-            if (mFeatureWeights == null) {
-                mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
-                mFeatureWeights = new ArrayMap<>(featureSize);
-                for (int i = 0; i < featureSize; i++) {
-                    String featureName = target.keyAt(i);
-                    float weight = mParamSharedPref.getFloat(featureName, 0.0f);
-                    sum += weight * target.valueAt(i);
-                    mFeatureWeights.put(featureName, weight);
-                }
-            } else {
-                for (int i = 0; i < featureSize; i++) {
-                    String featureName = target.keyAt(i);
-                    float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
-                    sum += weight * target.valueAt(i);
-                }
+            for (int i = 0; i < featureSize; i++) {
+                String featureName = target.keyAt(i);
+                float weight = mFeatureWeights.getOrDefault(featureName, 0.0f);
+                sum += weight * target.valueAt(i);
             }
             return (float) (1.0 / (1.0 + Math.exp(-mBias - sum)));
         }
 
         public void update(ArrayMap<String, Float> target, float predict, boolean isSelected) {
-            if (target == null || target.size() == 0) {
+            if (target == null) {
                 return;
             }
             final int featureSize = target.size();
-            if (mFeatureWeights == null) {
-                mBias = 0.0f;
-                mFeatureWeights = new ArrayMap<>(featureSize);
-            }
             float error = isSelected ? 1.0f - predict : -predict;
             for (int i = 0; i < featureSize; i++) {
                 String featureName = target.keyAt(i);
@@ -405,15 +394,13 @@
         }
 
         public void commitUpdate() {
-            if (mFeatureWeights == null || mFeatureWeights.size() == 0) {
-                return;
-            }
             SharedPreferences.Editor editor = mParamSharedPref.edit();
             editor.putFloat(BIAS_PREF_KEY, mBias);
             final int size = mFeatureWeights.size();
             for (int i = 0; i < size; i++) {
                 editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i));
             }
+            editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION);
             editor.apply();
         }
 
@@ -431,5 +418,27 @@
                     PARAM_SHARED_PREF_NAME + ".xml");
             return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
         }
+
+        private void initModel() {
+            mFeatureWeights = new ArrayMap<>(4);
+            if (mParamSharedPref == null ||
+                    mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) {
+                // Initializing the app ranker to a pre-trained model. When updating the pre-trained
+                // model, please increment CURRENT_VERSION, and update LEARNING_RATE and
+                // REGULARIZER_PARAM.
+                mBias = -1.6568f;
+                mFeatureWeights.put(LAUNCH_SCORE, 2.5543f);
+                mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f);
+                mFeatureWeights.put(RECENCY_SCORE, 0.269f);
+                mFeatureWeights.put(CHOOSER_SCORE, 4.2222f);
+            } else {
+                mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f);
+                mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f));
+                mFeatureWeights.put(
+                        TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f));
+                mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f));
+                mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f));
+            }
+        }
     }
 }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index f88f6f9..00faf65 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -19,13 +19,16 @@
 
 import android.annotation.WorkerThread;
 import android.app.ActivityManager;
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.RemoteException;
 import android.util.Log;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -66,6 +69,22 @@
     }
 
     @VisibleForTesting
+    ResolveInfo getLastChosen() throws RemoteException {
+        return AppGlobals.getPackageManager().getLastChosenActivity(
+                mTargetIntent, mTargetIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                PackageManager.MATCH_DEFAULT_ONLY);
+    }
+
+    @VisibleForTesting
+    void setLastChosen(Intent intent, IntentFilter filter, int match)
+            throws RemoteException {
+        AppGlobals.getPackageManager().setLastChosenActivity(intent,
+                intent.resolveType(mContext.getContentResolver()),
+                PackageManager.MATCH_DEFAULT_ONLY,
+                filter, match, intent.getComponent());
+    }
+
+    @VisibleForTesting
     public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntent(
             boolean shouldGetResolvedFilter,
             boolean shouldGetActivityMetadata,
diff --git a/core/java/com/android/internal/font/IFontManager.aidl b/core/java/com/android/internal/font/IFontManager.aidl
new file mode 100644
index 0000000..52a6262
--- /dev/null
+++ b/core/java/com/android/internal/font/IFontManager.aidl
@@ -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.
+ */
+
+package com.android.internal.font;
+
+import android.text.FontConfig;
+
+/**
+ * Interface to the font manager.
+ * @hide
+ */
+interface IFontManager {
+    FontConfig getSystemFonts();
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 716997f..c08cd72 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -1080,22 +1080,6 @@
             return enabledSubtypes;
         }
 
-        // At the initial boot, the settings for input methods are not set,
-        // so we need to enable IME in that case.
-        public void enableAllIMEsIfThereIsNoEnabledIME() {
-            if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
-                StringBuilder sb = new StringBuilder();
-                final int N = mMethodList.size();
-                for (int i = 0; i < N; i++) {
-                    InputMethodInfo imi = mMethodList.get(i);
-                    Slog.i(TAG, "Adding: " + imi.getId());
-                    if (i > 0) sb.append(':');
-                    sb.append(imi.getId());
-                }
-                putEnabledInputMethodsStr(sb.toString());
-            }
-        }
-
         public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
             return buildInputMethodsAndSubtypeList(getEnabledInputMethodsStr(),
                     mInputMethodSplitter,
diff --git a/core/java/com/android/internal/logging/LogBuilder.java b/core/java/com/android/internal/logging/LogBuilder.java
index 8e2e114..2d78979 100644
--- a/core/java/com/android/internal/logging/LogBuilder.java
+++ b/core/java/com/android/internal/logging/LogBuilder.java
@@ -1,12 +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 com.android.internal.logging;
 
 import android.util.EventLog;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 
+
 /**
  * Helper class to assemble more complex logs.
  *
@@ -14,6 +31,13 @@
  */
 
 public class LogBuilder {
+    private static final String TAG = "LogBuilder";
+
+    // Min required eventlog line length.
+    // See: android/util/cts/EventLogTest.java
+    // Size checks enforced here are intended only as sanity checks;
+    // your logs may be truncated earlier. Please log responsibly.
+    public static final int MAX_SERIALIZED_SIZE = 4000;
 
     private SparseArray<Object> entries = new SparseArray();
 
@@ -21,9 +45,9 @@
         setCategory(mainCategory);
     }
 
-    public LogBuilder setView(View view) {
-        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VIEW, view.getId());
-        return this;
+    /* Deserialize from the eventlog */
+    public LogBuilder(Object[] items) {
+      deserialize(items);
     }
 
     public LogBuilder setCategory(int category) {
@@ -36,23 +60,147 @@
         return this;
     }
 
+    public LogBuilder setSubtype(int subtype) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE, subtype);
+        return this;
+    }
+
+    public LogBuilder setTimestamp(long timestamp) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP, timestamp);
+        return this;
+    }
+
+    public LogBuilder setPackageName(String packageName) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME, packageName);
+        return this;
+    }
+
+    public LogBuilder setCounterName(String name) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME, name);
+        return this;
+    }
+
+    public LogBuilder setCounterBucket(int bucket) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET, bucket);
+        return this;
+    }
+
+    public LogBuilder setCounterBucket(long bucket) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET, bucket);
+        return this;
+    }
+
+    public LogBuilder setCounterValue(int value) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VALUE, value);
+        return this;
+    }
+
     /**
      * @param tag From your MetricsEvent enum.
      * @param value One of Integer, Long, Float, String
      * @return
      */
     public LogBuilder addTaggedData(int tag, Object value) {
-        if (!(value instanceof Integer ||
-            value instanceof String ||
-            value instanceof Long ||
-            value instanceof Float)) {
+        if (isValidValue(value)) {
             throw new IllegalArgumentException(
                     "Value must be loggable type - int, long, float, String");
         }
-        entries.put(tag, value);
+        if (value.toString().getBytes().length > MAX_SERIALIZED_SIZE) {
+            Log.i(TAG, "Log value too long, omitted: " + value.toString());
+        } else {
+            entries.put(tag, value);
+        }
         return this;
     }
 
+    public boolean isValidValue(Object value) {
+        return !(value instanceof Integer ||
+            value instanceof String ||
+            value instanceof Long ||
+            value instanceof Float);
+    }
+
+    public Object getTaggedData(int tag) {
+        return entries.get(tag);
+    }
+
+    public int getCategory() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return MetricsEvent.VIEW_UNKNOWN;
+        }
+    }
+
+    public int getType() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return MetricsEvent.TYPE_UNKNOWN;
+        }
+    }
+
+    public int getSubtype() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return 0;
+        }
+    }
+
+    public long getTimestamp() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP);
+        if (obj instanceof Long) {
+            return (Long) obj;
+        } else {
+            return 0;
+        }
+    }
+
+    public String getPackageName() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME);
+        if (obj instanceof String) {
+            return (String) obj;
+        } else {
+            return null;
+        }
+    }
+
+    public String getCounterName() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME);
+        if (obj instanceof String) {
+            return (String) obj;
+        } else {
+            return null;
+        }
+    }
+
+    public long getCounterBucket() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET);
+        if (obj instanceof Number) {
+            return ((Number) obj).longValue();
+        } else {
+            return 0L;
+        }
+    }
+
+    public boolean isLongCounterBucket() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET);
+        return obj instanceof Long;
+    }
+
+    public int getCounterValue() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_VALUE);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return 0;
+        }
+    }
+
     /**
      * Assemble logs into structure suitable for EventLog.
      */
@@ -62,7 +210,24 @@
             out[i * 2] = entries.keyAt(i);
             out[i * 2 + 1] = entries.valueAt(i);
         }
+        int size = out.toString().getBytes().length;
+        if (size > MAX_SERIALIZED_SIZE) {
+            Log.i(TAG, "Log line too long, did not emit: " + size + " bytes.");
+            throw new RuntimeException();
+        }
         return out;
     }
-}
 
+    public void deserialize(Object[] items) {
+        int i = 0;
+        while (i < items.length) {
+            Object key = items[i++];
+            Object value = i < items.length ? items[i++] : null;
+            if (key instanceof Integer) {
+                entries.put((Integer) key, value);
+            } else {
+                Log.i(TAG, "Invalid key " + key.toString());
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 5eb39ae..b90336c 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -17,12 +17,10 @@
 
 import android.content.Context;
 import android.os.Build;
-import android.util.EventLog;
 import android.view.View;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
-
 /**
  * Log all the things.
  *
@@ -38,6 +36,10 @@
             throw new IllegalArgumentException("Must define metric category");
         }
         EventLogTags.writeSysuiViewVisibility(category, 100);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_OPEN)
+                        .serialize());
     }
 
     public static void hidden(Context context, int category) throws IllegalArgumentException {
@@ -45,6 +47,10 @@
             throw new IllegalArgumentException("Must define metric category");
         }
         EventLogTags.writeSysuiViewVisibility(category, 0);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_CLOSE)
+                        .serialize());
     }
 
     public static void visibility(Context context, int category, boolean visibile)
@@ -62,21 +68,35 @@
     }
 
     public static void action(Context context, int category) {
-        action(context, category, "");
+        EventLogTags.writeSysuiAction(category, "");
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .serialize());
     }
 
     public static void action(Context context, int category, int value) {
-        action(context, category, Integer.toString(value));
+        EventLogTags.writeSysuiAction(category, Integer.toString(value));
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .setSubtype(value)
+                        .serialize());
     }
 
     public static void action(Context context, int category, boolean value) {
-        action(context, category, Boolean.toString(value));
+        EventLogTags.writeSysuiAction(category, Boolean.toString(value));
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .setSubtype(value ? 1 : 0)
+                        .serialize());
     }
 
     public static void action(LogBuilder content) {
-        //EventLog.writeEvent(524292, content.serialize());
-        // Below would be the *right* way to do this, using the generated
-        // EventLogTags method, but that doesn't work.
+        if (content.getType() == MetricsEvent.TYPE_UNKNOWN) {
+            content.setType(MetricsEvent.TYPE_ACTION);
+        }
         EventLogTags.writeSysuiMultiAction(content.serialize());
     }
 
@@ -86,15 +106,30 @@
             throw new IllegalArgumentException("Must define metric category");
         }
         EventLogTags.writeSysuiAction(category, pkg);
+        EventLogTags.writeSysuiMultiAction(new LogBuilder(category)
+                .setType(MetricsEvent.TYPE_ACTION)
+                .setPackageName(pkg)
+                .serialize());
     }
 
     /** Add an integer value to the monotonically increasing counter with the given name. */
     public static void count(Context context, String name, int value) {
         EventLogTags.writeSysuiCount(name, value);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                        .setCounterName(name)
+                        .setCounterValue(value)
+                        .serialize());
     }
 
     /** Increment the bucket with the integer label on the histogram with the given name. */
     public static void histogram(Context context, String name, int bucket) {
         EventLogTags.writeSysuiHistogram(name, bucket);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                        .setCounterName(name)
+                        .setCounterBucket(bucket)
+                        .setCounterValue(1)
+                        .serialize());
     }
 }
diff --git a/core/java/com/android/internal/logging/MetricsReader.java b/core/java/com/android/internal/logging/MetricsReader.java
new file mode 100644
index 0000000..c4fc963
--- /dev/null
+++ b/core/java/com/android/internal/logging/MetricsReader.java
@@ -0,0 +1,64 @@
+/*
+ * 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.logging;
+
+import com.android.internal.logging.legacy.LegacyConversionLogger;
+import com.android.internal.logging.legacy.EventLogCollector;
+
+import java.util.Queue;
+
+/**
+ * Read platform logs.
+ */
+public class MetricsReader {
+    private EventLogCollector mReader;
+    private Queue<LogBuilder> mEventQueue;
+    private long mLastEventMs;
+    private long mCheckpointMs;
+
+    /** Open a new session and start reading logs.
+     *
+     * Starts reading from the oldest log not already read by this reader object.
+     * On first invocation starts from the oldest available log ion the system.
+     */
+    public void read(long startMs) {
+        EventLogCollector reader = EventLogCollector.getInstance();
+        LegacyConversionLogger logger = new LegacyConversionLogger();
+        mLastEventMs = reader.collect(logger, startMs);
+        mEventQueue = logger.getEvents();
+    }
+
+    public void checkpoint() {
+        read(0L);
+        mCheckpointMs = mLastEventMs;
+        mEventQueue = null;
+    }
+
+    public void reset() {
+        read(mCheckpointMs);
+    }
+
+    /* Does the current log session have another entry? */
+    public boolean hasNext() {
+        return mEventQueue == null ? false : !mEventQueue.isEmpty();
+    }
+
+    /* Next entry in the current log session. */
+    public LogBuilder next() {
+        return mEventQueue == null ? null : mEventQueue.remove();
+    }
+
+}
diff --git a/core/java/com/android/internal/logging/legacy/CounterParser.java b/core/java/com/android/internal/logging/legacy/CounterParser.java
new file mode 100644
index 0000000..f318503
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/CounterParser.java
@@ -0,0 +1,54 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+/**
+ * Parse the Android counter event logs.
+ * @hide
+ */
+public class CounterParser extends TagParser {
+    private static final String TAG = "CounterParser";
+    private static final int EVENTLOG_TAG = 524290;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 2) {
+            try {
+                String name = ((String) operands[0]);
+                int value = (Integer) operands[1];
+                logCount(logger, name, value);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.d(TAG, "unexpected operand type", e);
+                }
+            }
+        } else if (debug) {
+            Log.d(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+
+    protected void logCount(TronLogger logger, String name, int value) {
+        logger.incrementBy(TronCounters.TRON_AOSP_PREFIX + name, value);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/EventLogCollector.java b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
new file mode 100644
index 0000000..eba7d0f
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
@@ -0,0 +1,188 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Scan the event log for interaction metrics events.
+ * @hide
+ */
+public class EventLogCollector {
+    private static final String TAG = "EventLogCollector";
+
+    // TODO replace this with GoogleLogTags.TRON_HEARTBEAT
+    @VisibleForTesting
+    static final int TRON_HEARTBEAT = 208000;
+
+    private static EventLogCollector sInstance;
+
+    private final ArrayMap<Integer, TagParser> mTagParsers;
+    private int[] mInterestingTags;
+
+    private LogReader mLogReader;
+
+    private EventLogCollector() {
+        mTagParsers = new ArrayMap<>();
+        addParser(new SysuiViewVisibilityParser());
+        addParser(new SysuiActionParser());
+        addParser(new SysuiQueryParser());
+        addParser(new NotificationPanelRevealedParser());
+        addParser(new NotificationPanelHiddenParser());
+        addParser(new NotificationClickedParser());
+        addParser(new NotificationActionClickedParser());
+        addParser(new NotificationCanceledParser());
+        addParser(new NotificationVisibilityParser());
+        addParser(new NotificationAlertParser());
+        addParser(new NotificationExpansionParser());
+        addParser(new CounterParser());
+        addParser(new HistogramParser());
+        addParser(new LockscreenGestureParser());
+        addParser(new StatusBarStateParser());
+        addParser(new PowerScreenStateParser());
+        addParser(new SysuiMultiActionParser());
+
+        mLogReader = new LogReader();
+    }
+
+    public static EventLogCollector getInstance() {
+        if (sInstance == null) {
+            sInstance = new EventLogCollector();
+        }
+        return sInstance;
+    }
+
+    @VisibleForTesting
+    public void setLogReader(LogReader logReader) {
+        mLogReader = logReader;
+    }
+
+    private int[] getInterestingTags() {
+        if (mInterestingTags == null) {
+            mInterestingTags = new int[mTagParsers.size()];
+            for (int i = 0; i < mTagParsers.size(); i++) {
+                mInterestingTags[i] = mTagParsers.valueAt(i).getTag();
+            }
+        }
+        return mInterestingTags;
+    }
+
+    // I would customize ArrayMap to add put(TagParser), but ArrayMap is final.
+    @VisibleForTesting
+    void addParser(TagParser parser) {
+        mTagParsers.put(parser.getTag(), parser);
+        mInterestingTags = null;
+    }
+
+    public void collect(LegacyConversionLogger logger) {
+        collect(logger, 0L);
+    }
+
+    public long collect(TronLogger logger, long lastSeenEventMs) {
+        long lastEventMs = 0L;
+        final boolean debug = Util.debug();
+
+        if (debug) {
+            Log.d(TAG, "Eventlog Collection");
+        }
+        ArrayList<Event> events = new ArrayList<>();
+        try {
+            mLogReader.readEvents(getInterestingTags(), events);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        if (debug) {
+            Log.d(TAG, "read this many events: " + events.size());
+        }
+
+        for (Event event : events) {
+            final long millis = event.getTimeNanos() / 1000000;
+            if (millis > lastSeenEventMs) {
+                final int tag = event.getTag();
+                TagParser parser = mTagParsers.get(tag);
+                if (parser == null) {
+                    if (debug) {
+                        Log.d(TAG, "unknown tag: " + tag);
+                    }
+                    continue;
+                }
+                if (debug) {
+                    Log.d(TAG, "parsing tag: " + tag);
+                }
+                parser.parseEvent(logger, event);
+                lastEventMs = Math.max(lastEventMs, millis);
+            } else {
+                if (debug) {
+                    Log.d(TAG, "old event: " + millis + " < " + lastSeenEventMs);
+                }
+            }
+        }
+        return lastEventMs;
+    }
+
+    @VisibleForTesting
+    static class Event {
+        long mTimeNanos;
+        int mTag;
+        Object mData;
+
+        Event(long timeNanos, int tag, Object data) {
+            super();
+            mTimeNanos = timeNanos;
+            mTag = tag;
+            mData = data;
+        }
+
+        Event(EventLog.Event event) {
+            mTimeNanos = event.getTimeNanos();
+            mTag = event.getTag();
+            mData = event.getData();
+        }
+
+        public long getTimeNanos() {
+            return mTimeNanos;
+        }
+
+        public int getTag() {
+            return mTag;
+        }
+
+        public Object getData() {
+            return mData;
+        }
+    }
+
+    @VisibleForTesting
+    static class LogReader {
+        public void readEvents(int[] tags, Collection<Event> events) throws IOException {
+            // Testing in Android: the Static Final Class Strikes Back!
+            ArrayList<EventLog.Event> nativeEvents = new ArrayList<>();
+            EventLog.readEventsOnWrapping(tags, 0L, nativeEvents);
+            for (EventLog.Event nativeEvent : nativeEvents) {
+                Event event = new Event(nativeEvent);
+                events.add(event);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/HistogramParser.java b/core/java/com/android/internal/logging/legacy/HistogramParser.java
new file mode 100644
index 0000000..bb7e75c
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/HistogramParser.java
@@ -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.logging.legacy;
+
+/**
+ * Parse the Android histogram event logs.
+ * @hide
+ */
+public class HistogramParser extends CounterParser {
+    private static final String TAG = "HistogramParser";
+    private static final int EVENTLOG_TAG = 524291;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    protected void logCount(TronLogger logger, String name, int value) {
+        logger.incrementIntHistogram("tron_varz_" + name, value);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
new file mode 100644
index 0000000..7381ff0
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.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.internal.logging.legacy;
+
+import android.os.Bundle;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Queue;
+
+/** @hide */
+public class LegacyConversionLogger implements TronLogger {
+    public static final String VIEW_KEY = "view";
+    public static final String TYPE_KEY = "type";
+    public static final String EVENT_KEY = "data";
+
+    public static final int TYPE_COUNTER = 1;
+    public static final int TYPE_HISTOGRAM = 2;
+    public static final int TYPE_EVENT = 3;
+
+    private final Queue<LogBuilder> mQueue;
+    private HashMap<String, Boolean> mConfig;
+
+    public LegacyConversionLogger() {
+        mQueue = new LinkedList<>();
+    }
+
+    public Queue<LogBuilder> getEvents() {
+        return mQueue;
+    }
+
+    @Override
+    public void increment(String counterName) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                .setCounterName(counterName)
+                .setCounterValue(1);
+        mQueue.add(b);
+    }
+
+    @Override
+    public void incrementBy(String counterName, int value) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                .setCounterName(counterName)
+                .setCounterValue(value);
+        mQueue.add(b);
+    }
+
+    @Override
+    public void incrementIntHistogram(String counterName, int bucket) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                .setCounterName(counterName)
+                .setCounterBucket(bucket)
+                .setCounterValue(1);
+        mQueue.add(b);
+    }
+
+    @Override
+    public void incrementLongHistogram(String counterName, long bucket) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                .setCounterName(counterName)
+                .setCounterBucket(bucket)
+                .setCounterValue(1);
+        mQueue.add(b);
+    }
+
+    @Override
+    public LogBuilder obtain() {
+        return new LogBuilder(MetricsEvent.VIEW_UNKNOWN);
+    }
+
+    @Override
+    public void dispose(LogBuilder proto) {
+    }
+
+    @Override
+    public void addEvent(LogBuilder proto) {
+        mQueue.add(proto);
+    }
+
+    @Override
+    public boolean getConfig(String configName) {
+        if (mConfig != null && mConfig.containsKey(configName)) {
+            return mConfig.get(configName);
+        }
+        return false;
+    }
+
+    @Override
+    public void setConfig(String configName, boolean newValue) {
+        if (mConfig == null) {
+            mConfig = new HashMap<>();
+        }
+        mConfig.put(configName, newValue);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java b/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java
new file mode 100644
index 0000000..6bede24
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java
@@ -0,0 +1,80 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android lockscreen gesture logs.
+ * @hide
+ */
+public class LockscreenGestureParser extends TagParser {
+    private static final String TAG = "LockscreenGestureParser";
+    private static final int EVENTLOG_TAG = 36021;
+
+    // source of truth is com.android.systemui.EventLogConstants
+    public static final int[] GESTURE_TYPE_MAP = {
+            MetricsEvent.VIEW_UNKNOWN,  // there is no type 0
+            MetricsEvent.ACTION_LS_UNLOCK,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK = 1
+            MetricsEvent.ACTION_LS_SHADE,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE = 2
+            MetricsEvent.ACTION_LS_HINT,  // SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT = 3
+            MetricsEvent.ACTION_LS_CAMERA,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA = 4
+            MetricsEvent.ACTION_LS_DIALER,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER = 5
+            MetricsEvent.ACTION_LS_LOCK,  // SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6
+            MetricsEvent.ACTION_LS_NOTE,  // SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7
+            MetricsEvent.ACTION_LS_QS,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8
+            MetricsEvent.ACTION_SHADE_QS_PULL,  // SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9
+            MetricsEvent.ACTION_SHADE_QS_TAP  // SYSUI_TAP_TO_OPEN_QS = 10
+    };
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 1) {
+            try {
+                int type = ((Integer) operands[0]).intValue();
+                // ignore gesture length in operands[1]
+                // ignore gesture velocity in operands[2]
+
+                int category = MetricsEvent.VIEW_UNKNOWN;
+                if (type < GESTURE_TYPE_MAP.length) {
+                    category = GESTURE_TYPE_MAP[type];
+                }
+                if (category != MetricsEvent.VIEW_UNKNOWN) {
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(category);
+                    proto.setType(MetricsEvent.TYPE_ACTION);
+                    proto.setTimestamp(eventTimeMs);
+                    logger.addEvent(proto);
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java b/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java
new file mode 100644
index 0000000..67b84e9
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification action button interaction event logs.
+ * @hide
+ */
+public class NotificationActionClickedParser extends TagParser {
+    private static final String TAG = "NotificationAction";
+    private static final int EVENTLOG_TAG = 27521;
+
+    private final NotificationKey mKey;
+
+    public NotificationActionClickedParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 1) {
+            try {
+                if (mKey.parse((String) operands[0])) {
+                    int index = (Integer) operands[1];
+                    parseTimes(operands, 2);
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION);
+                    proto.setType(MetricsEvent.TYPE_ACTION);
+                    proto.setSubtype(index);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key.");
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java b/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java
new file mode 100644
index 0000000..761197b
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java
@@ -0,0 +1,86 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the new Android notification alert event logs.
+ * @hide
+ */
+public class NotificationAlertParser extends TagParser {
+    private static final String TAG = "NotificationAlertParser";
+    private static final int EVENTLOG_TAG = 27532;
+
+    @VisibleForTesting
+    static final int BUZZ = 0x00000001;
+    @VisibleForTesting
+    static final int BEEP = 0x00000002;
+    @VisibleForTesting
+    static final int BLINK = 0x00000004;
+
+    private final NotificationKey mKey;
+
+    public NotificationAlertParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 3) {
+            try {
+                final String keyString = (String) operands[0];
+                final boolean buzz = ((Integer) operands[1]) == 1;
+                final boolean beep = ((Integer) operands[2]) == 1;
+                final boolean blink = ((Integer) operands[3]) == 1;
+
+                if (mKey.parse(keyString)) {
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ALERT);
+                    proto.setType(MetricsEvent.TYPE_OPEN);
+                    proto.setSubtype((buzz ? BUZZ : 0) | (beep ? BEEP : 0) | (blink ? BLINK : 0));
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else {
+                    if (debug) {
+                        Log.e(TAG, "unable to parse key: " + keyString);
+                    }
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+                return;
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java b/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java
new file mode 100644
index 0000000..0cab1a8
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java
@@ -0,0 +1,102 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification cancellation event logs.
+ * @hide
+ */
+public class NotificationCanceledParser extends TagParser {
+    private static final String TAG = "NotificationCanceled";
+    private static final int EVENTLOG_TAG = 27530;
+
+    // from com.android.server.notification.NotificationManagerService
+    static final int REASON_DELEGATE_CLICK = 1;
+    static final int REASON_DELEGATE_CANCEL = 2;
+    static final int REASON_DELEGATE_CANCEL_ALL = 3;
+    static final int REASON_PACKAGE_BANNED = 7;
+    static final int REASON_LISTENER_CANCEL = 10;
+    static final int REASON_LISTENER_CANCEL_ALL = 11;
+
+    private final NotificationKey mKey;
+
+    public NotificationCanceledParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 1) {
+            try {
+                final String keyString = (String) operands[0];
+                final int reason = (Integer) operands[1];
+                parseTimes(operands, 2);
+
+                // handle old style log
+                // TODO: delete once M is launched
+                if (operands.length < 5) {
+                    mSinceVisibleMillis = mSinceUpdateMillis;
+                    mSinceUpdateMillis = 0;
+                }
+
+                boolean intentional = true;
+                switch (reason) {
+                    case REASON_DELEGATE_CANCEL:
+                    case REASON_DELEGATE_CANCEL_ALL:
+                    case REASON_LISTENER_CANCEL:
+                    case REASON_LISTENER_CANCEL_ALL:
+                    case REASON_DELEGATE_CLICK:
+                    case REASON_PACKAGE_BANNED:
+                        break;
+                    default:
+                        intentional = false;
+                }
+
+                if (mKey.parse(keyString)) {
+                    if (intentional) {
+                        LogBuilder proto = logger.obtain();
+                        proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                        proto.setType(MetricsEvent.TYPE_DISMISS);
+                        proto.setSubtype(reason);
+                        proto.setTimestamp(eventTimeMs);
+                        proto.setPackageName(mKey.mPackageName);
+                        proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                        proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                        filltimes(proto);
+                        logger.addEvent(proto);
+                    }
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key: " + keyString);
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java b/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java
new file mode 100644
index 0000000..eeae0a8
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java
@@ -0,0 +1,70 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification interaction event logs.
+ * @hide
+ */
+public class NotificationClickedParser extends TagParser {
+    private static final String TAG = "NotificationClicked";
+    private static final int EVENTLOG_TAG = 27520;
+
+    private final NotificationKey mKey;
+
+    public NotificationClickedParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 0) {
+            try {
+                if (mKey.parse((String) operands[0])) {
+                    parseTimes(operands, 1);
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                    proto.setType(MetricsEvent.TYPE_ACTION);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key.");
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java b/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java
new file mode 100644
index 0000000..d44b8b1
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java
@@ -0,0 +1,76 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification expansion event logs.
+ * @hide
+ */
+public class NotificationExpansionParser extends TagParser {
+    private static final String TAG = "NotificationExpansion";
+    private static final int EVENTLOG_TAG = 27511;
+
+    private final NotificationKey mKey;
+
+    public NotificationExpansionParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 2) {
+            try {
+                if (mKey.parse((String) operands[0])) {
+                    boolean byUser = ((Integer) operands[1]) == 1;
+                    boolean expanded = ((Integer) operands[2]) == 1;
+                    parseTimes(operands, 3);
+
+                    if (!byUser || !expanded) {
+                        return;
+                    }
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                    proto.setType(MetricsEvent.TYPE_DETAIL);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key.");
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationKey.java b/core/java/com/android/internal/logging/legacy/NotificationKey.java
new file mode 100644
index 0000000..f8cac34
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationKey.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.internal.logging.legacy;
+
+import android.util.Log;
+
+/**
+ * Parse Android notification keys
+ * @hide
+ */
+public class NotificationKey {
+
+    private static final String TAG = "NotificationKey";
+
+    public int mUser;
+    public String mPackageName;
+    public int mId;
+    public String mTag;
+    public int mUid;
+
+    public boolean parse(String key) {
+        if (key == null) {
+            return false;
+        }
+        boolean debug = Util.debug();
+        String[] parts = key.split("\\|");
+        if (parts.length == 5) {
+            try {
+                mUser = Integer.valueOf(parts[0]);
+                mPackageName = parts[1];
+                mId = Integer.valueOf(parts[2]);
+                mTag = parts[3].equals("null") ? "" : parts[3];
+                mUid = Integer.valueOf(parts[4]);
+                return true;
+            } catch (NumberFormatException e) {
+                if (debug) {
+                    Log.w(TAG, "could not parse notification key.", e);
+                }
+                return false;
+            }
+        }
+        if (debug) {
+            Log.w(TAG, "wrong number of parts in notification key: " + key);
+        }
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java b/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java
new file mode 100644
index 0000000..662295b
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java
@@ -0,0 +1,42 @@
+/*
+ * 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.logging.legacy;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification panel visibility event logs.
+ * @hide
+ */
+public class NotificationPanelHiddenParser extends TagParser {
+    private static final String TAG = "NotificationPanelHidden";
+    private static final int EVENTLOG_TAG = 27501;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        LogBuilder proto = logger.obtain();
+        proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
+        proto.setType(MetricsEvent.TYPE_CLOSE);
+        proto.setTimestamp(eventTimeMs);
+        logger.addEvent(proto);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java b/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java
new file mode 100644
index 0000000..0566f0b
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java
@@ -0,0 +1,56 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification panel visibility event logs.
+ * @hide
+ */
+public class NotificationPanelRevealedParser extends TagParser {
+    private static final String TAG = "NotificationPanelRevea";
+    private static final int EVENTLOG_TAG = 27500;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 1) {
+            try {
+                int load = ((Integer) operands[0]).intValue();
+                //logger.incrementBy(TronCounters.TRON_NOTIFICATION_LOAD, load);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        }
+
+        LogBuilder proto = logger.obtain();
+        proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
+        proto.setType(MetricsEvent.TYPE_OPEN);
+        proto.setTimestamp(eventTimeMs);
+        logger.addEvent(proto);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java b/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java
new file mode 100644
index 0000000..9185b91
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java
@@ -0,0 +1,81 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the new Android notification visibility event logs.
+ * @hide
+ */
+public class NotificationVisibilityParser extends TagParser {
+    private static final String TAG = "NotificationVisibility";
+    private static final int EVENTLOG_TAG = 27531;
+
+    private final NotificationKey mKey;
+
+    public NotificationVisibilityParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 1) {
+            try {
+                final String keyString = (String) operands[0];
+                final boolean visible = ((Integer) operands[1]) == 1;
+                parseTimes(operands, 2);
+                int index = 0;
+                if (operands.length > 5 && operands[5] instanceof Integer) {
+                    index = (Integer) operands[5];
+                }
+
+                if (mKey.parse(keyString)) {
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                    proto.setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, index);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else {
+                    if (debug) {
+                        Log.e(TAG, "unable to parse key: " + keyString);
+                    }
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+                return;
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java b/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java
new file mode 100644
index 0000000..3bf0f9d
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.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 com.android.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android lockscreen gesture logs.
+ * @hide
+ */
+public class PowerScreenStateParser extends TagParser {
+    private static final String TAG = "PowerScreenStateParser";
+    private static final int EVENTLOG_TAG = 2728;
+
+    // source of truth is android.view.WindowManagerPolicy, why:
+    // 0: on
+    // 1: OFF_BECAUSE_OF_ADMIN
+    // 2: OFF_BECAUSE_OF_USER
+    // 3: OFF_BECAUSE_OF_TIMEOUT
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 2) {
+            try {
+                // (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
+                boolean state = (((Integer) operands[0]).intValue()) == 1;
+                int why = ((Integer) operands[1]).intValue();
+
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(MetricsEvent.SCREEN);
+                proto.setType(state ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
+                proto.setTimestamp(eventTimeMs);
+                proto.setSubtype(why);
+                logger.addEvent(proto);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java b/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java
new file mode 100644
index 0000000..23abec4
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/StatusBarStateParser.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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android lockscreen gesture logs.
+ * @hide
+ */
+public class StatusBarStateParser extends TagParser {
+    private static final String TAG = "StatusBarStateParser";
+    private static final int EVENTLOG_TAG = 36004;
+
+    // source of truth is com.android.systemui.statusbar.StatusBarState
+    public static final int SHADE = 0;
+    public static final int KEYGUARD = 1;
+    public static final int SHADE_LOCKED = 2;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 6) {
+            try {
+                // [state, isShowing, isOccluded, isBouncerShowing, isSecure, isCurrentlyInsecure]
+                int state = ((Integer) operands[0]).intValue();
+                boolean isBouncerShowing = (((Integer) operands[3]).intValue()) == 1;
+                int isSecure = ((Integer) operands[4]).intValue();
+
+                int view = MetricsEvent.LOCKSCREEN;
+                int type = MetricsEvent.TYPE_OPEN;
+                if (state == SHADE) {
+                    type = MetricsEvent.TYPE_CLOSE;
+                } else if (isBouncerShowing) {
+                    view = MetricsEvent.BOUNCER;
+                }
+
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(view);
+                proto.setType(type);
+                proto.setTimestamp(eventTimeMs);
+                proto.setSubtype(isSecure);
+                logger.addEvent(proto);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiActionParser.java b/core/java/com/android/internal/logging/legacy/SysuiActionParser.java
new file mode 100644
index 0000000..7f91f92
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiActionParser.java
@@ -0,0 +1,81 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android framework sysui action logs.
+ * @hide
+ */
+public class SysuiActionParser extends TagParser {
+    private static final String TAG = "SysuiActionParser";
+    private static final int EVENTLOG_TAG = 524288;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        try {
+            String packageName = null;
+            int subType = -1;
+            boolean hasSubType = false;
+            if (operands.length > 1) {
+                String arg = (String) operands[1];
+                if (arg.equals("true")) {
+                    hasSubType = true;
+                    subType = 1;
+                } else if (arg.equals("false")) {
+                    hasSubType = true;
+                    subType = 0;
+                } else if (arg.matches("^-?\\d+$")) {
+                    try {
+                        subType = Integer.valueOf(arg);
+                        hasSubType = true;
+                    } catch (NumberFormatException e) {
+                    }
+                } else {
+                    packageName = arg;
+                }
+            }
+            if (operands.length > 0) {
+                int category = ((Integer) operands[0]).intValue();
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(category);
+                proto.setType(MetricsEvent.TYPE_ACTION);
+                proto.setTimestamp(eventTimeMs);
+                if (packageName != null) {
+                    proto.setPackageName(packageName);
+                }
+                if (hasSubType) {
+                    proto.setSubtype(subType);
+                }
+                logger.addEvent(proto);
+            }
+        } catch (ClassCastException e) {
+            if (debug) {
+                Log.e(TAG, "unexpected operand type: ", e);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java b/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java
new file mode 100644
index 0000000..f9b2f49
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java
@@ -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.
+ */
+package com.android.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * ...and one parser to rule them all.
+ *
+ * This should, at some point in the future, be the only parser.
+ * @hide
+ */
+public class SysuiMultiActionParser extends TagParser {
+    private static final String TAG = "SysuiMultiActionParser";
+    private static final int EVENTLOG_TAG = 524292;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        try {
+            logger.addEvent(new LogBuilder(operands).setTimestamp(eventTimeMs));
+        } catch (ClassCastException e) {
+            if (debug) {
+                Log.e(TAG, "unexpected operand type: ", e);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java b/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java
new file mode 100644
index 0000000..7b3c0a7
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java
@@ -0,0 +1,32 @@
+/*
+ * 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.logging.legacy;
+
+/**
+ * Parse the Android framework sysui search query logs.
+ * For now just treat them like actions.
+ * @hide
+ */
+public class SysuiQueryParser extends SysuiActionParser {
+    private static final String TAG = "SysuiQueryParser";
+
+    private static final int EVENTLOG_TAG = 524289;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java b/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java
new file mode 100644
index 0000000..5d5aec0
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java
@@ -0,0 +1,58 @@
+/*
+ * 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.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android framework sysui view visibility logs.
+ * @hide
+ */
+public class SysuiViewVisibilityParser extends TagParser {
+    private static final String TAG = "SysuiViewVisibility";
+    private static final int EVENTLOG_TAG = 524287;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 2) {
+            try {
+                int category = ((Integer) operands[0]).intValue();
+                boolean visibility = ((Integer) operands[1]).intValue() != 0;
+
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(category);
+                proto.setType(visibility ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
+                proto.setTimestamp(eventTimeMs);
+                logger.addEvent(proto);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/TagParser.java b/core/java/com/android/internal/logging/legacy/TagParser.java
new file mode 100755
index 0000000..c62d084
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/TagParser.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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Abstraction layer between EventLog static classes and the actual TagParsers.
+ * @hide
+ */
+public abstract class TagParser {
+    private static final String TAG = "TagParser";
+
+    protected int mSinceCreationMillis;
+    protected int mSinceUpdateMillis;
+    protected int mSinceVisibleMillis;
+
+    abstract int getTag();
+
+    @VisibleForTesting
+    abstract public void parseEvent(TronLogger logger, long eventTimeMs, Object[] objects);
+
+    /**
+     * Parse the event into the proto: return true if proto was modified.
+     */
+    public void  parseEvent(TronLogger logger, EventLogCollector.Event event) {
+        final boolean debug = Util.debug();
+        Object data = event.getData();
+        Object[] objects;
+        if (data instanceof Object[]) {
+            objects = (Object[]) data;
+            for (int i = 0; i < objects.length; i++) {
+                if (objects[i] == null) {
+                    if (debug) {
+                        Log.d(TAG, "unexpected null value:" + event.getTag());
+                    }
+                    return;
+                }
+            }
+        } else {
+            // wrap scalar objects
+            objects = new Object[1];
+            objects[0] = data;
+        }
+
+        parseEvent(logger, event.getTimeNanos() / 1000000, objects);
+    }
+
+    protected void resetTimes() {
+        mSinceCreationMillis = 0;
+        mSinceUpdateMillis = 0;
+        mSinceVisibleMillis = 0;
+    }
+
+    public void parseTimes(Object[] operands, int index) {
+        resetTimes();
+
+        if (operands.length > index && operands[index] instanceof Integer) {
+            mSinceCreationMillis = (Integer) operands[index];
+        }
+
+        index++;
+        if (operands.length > index && operands[index] instanceof Integer) {
+            mSinceUpdateMillis = (Integer) operands[index];
+        }
+
+        index++;
+        if (operands.length > index && operands[index] instanceof Integer) {
+            mSinceVisibleMillis = (Integer) operands[index];
+        }
+    }
+
+   public void filltimes(LogBuilder proto) {
+        if (mSinceCreationMillis != 0) {
+            proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS,
+                    mSinceCreationMillis);
+        }
+        if (mSinceUpdateMillis != 0) {
+            proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS,
+                    mSinceUpdateMillis);
+        }
+        if (mSinceVisibleMillis != 0) {
+            proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS,
+                    mSinceVisibleMillis);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/TronCounters.java b/core/java/com/android/internal/logging/legacy/TronCounters.java
new file mode 100644
index 0000000..e0828a2
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/TronCounters.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.internal.logging.legacy;
+
+/**
+ * Names of the counters that the Tron package defines.
+ *
+ * Other counter names may be generated by AOSP code.
+ * @hide
+ */
+public class TronCounters {
+
+    static final String TRON_COLLECTIONS = "tron_collections";
+
+    static final String TRON_COLLECTION_PERIOD = "tron_collection_period_minutes";
+
+    static final String TRON_EVENTLOG_LENGTH = "tron_eventlog_horizon";
+
+    static final String TRON_NOTE_DISMISS = "tron_note_dismiss";
+
+    static final String TRON_NOTE_DISMISS_BY_USER = "tron_note_dismiss_user";
+
+    static final String TRON_NOTE_DISMISS_BY_CLICK = "tron_note_dismiss_click";
+
+    static final String TRON_NOTE_DISMISS_BY_LISTENER = "tron_note_dismiss_listener";
+
+    static final String TRON_NOTE_DISMISS_BY_BAN = "tron_note_dismiss_ban";
+
+    static final String TRON_NOTE_REVEALED = "tron_note_revealed";
+
+    static final String TRON_NOTIFICATION_LOAD = "tron_notification_load";
+
+    static final String TRON_VIEW = "tron_view";
+
+    static final String TRON_ACTION = "tron_action";
+
+    static final String TRON_DETAIL = "tron_detail";
+
+    static final String TRON_NOTE_LIFETIME = "tron_note_lifetime";
+
+    /** Append the AOSP-generated name */
+    static final String TRON_AOSP_PREFIX = "tron_varz_";
+
+    static final String TRON_ACTION_BAD_INT = "tron_action_bad_int";
+
+    static final String TRON_NOTE_FRESHNESS = "tron_note_freshness";
+
+    static final String TRON_NOTE_BUZZ = "tron_note_buzz";
+
+    static final String TRON_NOTE_BEEP = "tron_note_beep";
+
+    static final String TRON_NOTE_BLINK = "tron_note_blink";
+
+    static final String TRON_DISABLE = "tron_disable";
+
+    static final String TRON_LAST_HEART_AGE = "tron_last_heart_minutes";
+
+    static final String TRON_HEARTS_SEEN = "tron_hearts_seen";
+}
diff --git a/core/java/com/android/internal/logging/legacy/TronLogger.java b/core/java/com/android/internal/logging/legacy/TronLogger.java
new file mode 100644
index 0000000..dabe314
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/TronLogger.java
@@ -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.
+ */
+package com.android.internal.logging.legacy;
+
+import com.android.internal.logging.LogBuilder;
+
+/**
+ * An entity that knows how to log events and counters.
+ */
+public interface TronLogger {
+    /** Add one to the named counter. */
+    void increment(String counterName);
+
+    /** Add an arbitrary value to the named counter. */
+    void incrementBy(String counterName, int value);
+
+    /** Increment a specified bucket on the named histogram by one. */
+    void incrementIntHistogram(String counterName, int bucket);
+
+    /** Increment the specified bucket on the named histogram by one. */
+    void incrementLongHistogram(String counterName, long bucket);
+
+    /** Obtain a SystemUiEvent proto, must release this with dispose() or addEvent(). */
+    LogBuilder obtain();
+
+    void dispose(LogBuilder proto);
+
+    /** Submit an event to be logged. Logger will dispose of proto. */
+    void addEvent(LogBuilder proto);
+
+    /** Get a config flag. */
+    boolean getConfig(String configName);
+
+    /** Set a config flag. */
+    void setConfig(String configName, boolean newValue);
+}
diff --git a/core/java/com/android/internal/logging/legacy/Util.java b/core/java/com/android/internal/logging/legacy/Util.java
new file mode 100644
index 0000000..99f71ca
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/Util.java
@@ -0,0 +1,25 @@
+/*
+ * 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.logging.legacy;
+
+/**
+ * Created by cwren on 11/21/16.
+ */
+public class Util {
+    public static boolean debug() {
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/os/AppFuseMount.aidl b/core/java/com/android/internal/os/AppFuseMount.aidl
new file mode 100644
index 0000000..66cf95b
--- /dev/null
+++ b/core/java/com/android/internal/os/AppFuseMount.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.os;
+
+parcelable AppFuseMount;
diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java
index b392186..04d7211 100644
--- a/core/java/com/android/internal/os/AppFuseMount.java
+++ b/core/java/com/android/internal/os/AppFuseMount.java
@@ -19,14 +19,26 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
-import java.io.File;
+import android.os.storage.IStorageManager;
+import com.android.internal.util.Preconditions;
 
+/**
+ * Parcelable class representing AppFuse mount.
+ * This conveys the result for IStorageManager#openProxyFileDescriptor.
+ * @see IStorageManager#openProxyFileDescriptor
+ */
 public class AppFuseMount implements Parcelable {
-    final public File mountPoint;
+    final public int mountPointId;
     final public ParcelFileDescriptor fd;
 
-    public AppFuseMount(File mountPoint, ParcelFileDescriptor fd) {
-        this.mountPoint = mountPoint;
+    /**
+     * @param mountPointId Integer number for mount point that is unique in the lifetime of
+     *     StorageManagerService.
+     * @param fd File descriptor pointing /dev/fuse and tagged with the mount point.
+     */
+    public AppFuseMount(int mountPointId, ParcelFileDescriptor fd) {
+        Preconditions.checkNotNull(fd);
+        this.mountPointId = mountPointId;
         this.fd = fd;
     }
 
@@ -37,7 +49,7 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(this.mountPoint.getPath());
+        dest.writeInt(this.mountPointId);
         dest.writeParcelable(fd, flags);
     }
 
@@ -45,7 +57,7 @@
             new Parcelable.Creator<AppFuseMount>() {
         @Override
         public AppFuseMount createFromParcel(Parcel in) {
-            return new AppFuseMount(new File(in.readString()), in.readParcelable(null));
+            return new AppFuseMount(in.readInt(), in.readParcelable(null));
         }
 
         @Override
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 34253ce..3603b6d 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -18,34 +18,38 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.IProxyFileDescriptorCallback;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
 import android.util.SparseArray;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.concurrent.ThreadFactory;
 
 public class FuseAppLoop {
     private static final String TAG = "FuseAppLoop";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     public static final int ROOT_INODE = 1;
     private static final int MIN_INODE = 2;
+    private static final ThreadFactory sDefaultThreadFactory = new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+            return new Thread(r, TAG);
+        }
+    };
 
     private final Object mLock = new Object();
-    private final File mParent;
+    private final int mMountPointId;
+    private final Thread mThread;
 
     @GuardedBy("mLock")
     private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>();
 
-    @GuardedBy("mLock")
-    private boolean mActive = true;
-
     /**
      * Sequential number can be used as file name and inode in AppFuse.
      * 0 is regarded as an error, 1 is mount point. So we start the number from 2.
@@ -53,35 +57,40 @@
     @GuardedBy("mLock")
     private int mNextInode = MIN_INODE;
 
-    private FuseAppLoop(@NonNull File parent) {
-        mParent = parent;
-    }
-
-    public static @NonNull FuseAppLoop open(
-            @NonNull File parent, @NonNull ParcelFileDescriptor fd) {
-        Preconditions.checkNotNull(parent);
-        Preconditions.checkNotNull(fd);
-        final FuseAppLoop bridge = new FuseAppLoop(parent);
+    private FuseAppLoop(
+            int mountPointId, @NonNull ParcelFileDescriptor fd, @Nullable ThreadFactory factory) {
+        mMountPointId = mountPointId;
         final int rawFd = fd.detachFd();
-        new Thread(new Runnable() {
+        if (factory == null) {
+            factory = sDefaultThreadFactory;
+        }
+        mThread = factory.newThread(new Runnable() {
             @Override
             public void run() {
-                bridge.native_start_loop(rawFd);
+                // rawFd is closed by native_start_loop. Java code does not need to close it.
+                native_start_loop(rawFd);
             }
-        }, TAG).start();
-        return bridge;
+        });
     }
 
-    public @NonNull ParcelFileDescriptor openFile(int mode, IProxyFileDescriptorCallback callback)
+    public static @NonNull FuseAppLoop open(int mountPointId, @NonNull ParcelFileDescriptor fd,
+            @Nullable ThreadFactory factory) {
+        Preconditions.checkNotNull(fd);
+        final FuseAppLoop loop = new FuseAppLoop(mountPointId, fd, factory);
+        loop.mThread.start();
+        return loop;
+    }
+
+    public int registerCallback(@NonNull ProxyFileDescriptorCallback callback)
             throws UnmountedException, IOException {
-        int id;
+        if (mThread.getState() == Thread.State.TERMINATED) {
+            throw new UnmountedException();
+        }
         synchronized (mLock) {
-            if (!mActive) {
-                throw new UnmountedException();
-            }
             if (mCallbackMap.size() >= Integer.MAX_VALUE - MIN_INODE) {
                 throw new IOException("Too many opened files.");
             }
+            int id;
             while (true) {
                 id = mNextInode;
                 mNextInode++;
@@ -92,24 +101,17 @@
                     break;
                 }
             }
-
-            // Register callback after we succeed to create pfd.
             mCallbackMap.put(id, new CallbackEntry(callback));
-        }
-        try {
-            return ParcelFileDescriptor.open(new File(mParent, String.valueOf(id)), mode);
-        } catch (FileNotFoundException error) {
-            synchronized (mLock) {
-                mCallbackMap.remove(id);
-            }
-            throw error;
+            return id;
         }
     }
 
-    public @Nullable File getMountPoint() {
-        synchronized (mLock) {
-            return mActive ? mParent : null;
-        }
+    public void unregisterCallback(int id) {
+        mCallbackMap.remove(id);
+    }
+
+    public int getMountPointId() {
+        return mMountPointId;
     }
 
     private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
@@ -128,7 +130,7 @@
             try {
                 return getCallbackEntryOrThrowLocked(inode).callback.onGetSize();
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -147,7 +149,7 @@
                 // file twice.
                 return (int) inode;
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -160,7 +162,7 @@
                 getCallbackEntryOrThrowLocked(inode).callback.onFsync();
                 return 0;
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -169,12 +171,14 @@
     @SuppressWarnings("unused")
     private int onRelease(long inode) {
         synchronized(mLock) {
-            mCallbackMap.remove(checkInode(inode));
-            if (mCallbackMap.size() == 0) {
-                mActive = false;
-                return -1;
+            try {
+                getCallbackEntryOrThrowLocked(inode).callback.onRelease();
+                return 0;
+            } catch (ErrnoException exp) {
+                return getError(exp);
+            } finally {
+                mCallbackMap.remove(checkInode(inode));
             }
-            return 0;
         }
     }
 
@@ -185,7 +189,7 @@
             try {
                 return getCallbackEntryOrThrowLocked(inode).callback.onRead(offset, size, bytes);
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -197,11 +201,17 @@
             try {
                 return getCallbackEntryOrThrowLocked(inode).callback.onWrite(offset, size, bytes);
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
 
+    private static int getError(@NonNull ErrnoException exp) {
+        // Should not return ENOSYS because the kernel stops
+        // dispatching the FUSE action once FUSE implementation returns ENOSYS for the action.
+        return exp.errno != OsConstants.ENOSYS ? -exp.errno : -OsConstants.EIO;
+    }
+
     native boolean native_start_loop(int fd);
 
     private static int checkInode(long inode) {
@@ -212,9 +222,9 @@
     public static class UnmountedException extends Exception {}
 
     private static class CallbackEntry {
-        final IProxyFileDescriptorCallback callback;
+        final ProxyFileDescriptorCallback callback;
         boolean opened;
-        CallbackEntry(IProxyFileDescriptorCallback callback) {
+        CallbackEntry(ProxyFileDescriptorCallback callback) {
             Preconditions.checkNotNull(callback);
             this.callback = callback;
         }
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index c828d11..e8919ed 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -120,7 +120,7 @@
                             sb.append(" s=");
                             TimeUtils.formatDuration(systemTimeDeltaUs / 1000, sb);
                             sb.append(" p=").append(powerDeltaMaUs / 1000).append("mAms");
-                            Slog.wtf(TAG, sb.toString());
+                            Slog.e(TAG, sb.toString());
 
                             userTimeDeltaUs = 0;
                             systemTimeDeltaUs = 0;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8eb75c0..a3b066a 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -25,7 +25,6 @@
 import android.icu.text.DecimalFormatSymbols;
 import android.icu.util.ULocale;
 import android.net.LocalServerSocket;
-import android.opengl.EGL14;
 import android.os.IInstalld;
 import android.os.Process;
 import android.os.RemoteException;
@@ -125,9 +124,6 @@
         bootTimingsTraceLog.traceBegin("PreloadResources");
         preloadResources();
         bootTimingsTraceLog.traceEnd(); // PreloadResources
-        bootTimingsTraceLog.traceBegin("PreloadOpenGL");
-        preloadOpenGL();
-        bootTimingsTraceLog.traceEnd(); // PreloadOpenGL
         preloadSharedLibraries();
         preloadTextResources();
         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
@@ -177,12 +173,6 @@
         System.loadLibrary("jnigraphics");
     }
 
-    private static void preloadOpenGL() {
-        if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
-            EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
-        }
-    }
-
     private static void preloadTextResources() {
         Hyphenator.init();
         TextView.preloadFontCache();
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 4dd3360..6d13743 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -128,11 +128,14 @@
     /**
      * Applies the offset to the {@param stackBounds} to adjust it to a minimized state.
      */
-    public void applyMinimizedOffset(Rect stackBounds, Rect movementBounds, Point displaySize) {
+    public void applyMinimizedOffset(Rect stackBounds, Rect movementBounds, Point displaySize,
+            Rect stableInsets) {
         if (stackBounds.left <= movementBounds.centerX()) {
-            stackBounds.offsetTo(-stackBounds.width() + mMinimizedVisibleSize, stackBounds.top);
+            stackBounds.offsetTo(stableInsets.left + mMinimizedVisibleSize - stackBounds.width(),
+                    stackBounds.top);
         } else {
-            stackBounds.offsetTo(displaySize.x - mMinimizedVisibleSize, stackBounds.top);
+            stackBounds.offsetTo(displaySize.x - stableInsets.right - mMinimizedVisibleSize,
+                    stackBounds.top);
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index c8697dd..1fce0b7 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -48,7 +48,7 @@
     private MenuItem.OnMenuItemClickListener mClickListener;
 
     private CharSequence mContentDescription;
-    private CharSequence mTooltip;
+    private CharSequence mTooltipText;
 
     private static final int NO_ICON = 0;
 
@@ -290,13 +290,13 @@
     }
 
     @Override
-    public MenuItem setTooltip(CharSequence tooltip) {
-        mTooltip = tooltip;
+    public MenuItem setTooltipText(CharSequence tooltipText) {
+        mTooltipText = tooltipText;
         return this;
     }
 
     @Override
-    public CharSequence getTooltip() {
-        return mTooltip;
+    public CharSequence getTooltipText() {
+        return mTooltipText;
     }
 }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 4ee5993..92e1d80 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -193,12 +193,12 @@
             setContentDescription(contentDescription);
         }
 
-        final CharSequence tooltip = mItemData.getTooltip();
-        if (TextUtils.isEmpty(tooltip)) {
+        final CharSequence tooltipText = mItemData.getTooltipText();
+        if (TextUtils.isEmpty(tooltipText)) {
             // Use the uncondensed title for tooltip, but only if the title is not shown already.
-            setTooltip(visible ? null : mItemData.getTitle());
+            setTooltipText(visible ? null : mItemData.getTitle());
         } else {
-            setTooltip(tooltip);
+            setTooltipText(tooltipText);
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/IconMenuItemView.java b/core/java/com/android/internal/view/menu/IconMenuItemView.java
index f9ebdbc..6c8f330 100644
--- a/core/java/com/android/internal/view/menu/IconMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuItemView.java
@@ -113,7 +113,7 @@
             } else {
                 setContentDescription(contentDescription);
             }
-            setTooltip(mItemData.getTooltip());
+            setTooltipText(mItemData.getTooltipText());
         }
     }
 
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 7c9f709..43005e6 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -115,7 +115,7 @@
         setEnabled(itemData.isEnabled());
         setSubMenuArrowVisible(itemData.hasSubMenu());
         setContentDescription(itemData.getContentDescription());
-        setTooltip(itemData.getTooltip());
+        setTooltipText(itemData.getTooltipText());
     }
 
     public void setForceShowIcon(boolean forceShow) {
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index cad0276..342943f 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -94,7 +94,7 @@
     private ContextMenuInfo mMenuInfo;
 
     private CharSequence mContentDescription;
-    private CharSequence mTooltip;
+    private CharSequence mTooltipText;
 
     private static String sLanguage;
     private static String sPrependShortcutLabel;
@@ -689,8 +689,8 @@
     }
 
     @Override
-    public MenuItem setTooltip(CharSequence tooltip) {
-        mTooltip = tooltip;
+    public MenuItem setTooltipText(CharSequence tooltipText) {
+        mTooltipText = tooltipText;
 
         mMenu.onItemsChanged(false);
 
@@ -698,7 +698,7 @@
     }
 
     @Override
-    public CharSequence getTooltip() {
-        return mTooltip;
+    public CharSequence getTooltipText() {
+        return mTooltipText;
     }
 }
diff --git a/core/java/com/android/internal/widget/AdapterHelper.java b/core/java/com/android/internal/widget/AdapterHelper.java
new file mode 100644
index 0000000..f47d430
--- /dev/null
+++ b/core/java/com/android/internal/widget/AdapterHelper.java
@@ -0,0 +1,775 @@
+/*
+ * 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.widget;
+
+import android.util.Log;
+import android.util.Pools;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Helper class that can enqueue and process adapter update operations.
+ * <p>
+ * To support animations, RecyclerView presents an older version the Adapter to best represent
+ * previous state of the layout. Sometimes, this is not trivial when items are removed that were
+ * not laid out, in which case, RecyclerView has no way of providing that item's view for
+ * animations.
+ * <p>
+ * AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During
+ * pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass
+ * and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them
+ * according to previously deferred operation and dispatch them before the first layout pass. It
+ * also takes care of updating deferred UpdateOps since order of operations is changed by this
+ * process.
+ * <p>
+ * Although operations may be forwarded to LayoutManager in different orders, resulting data set
+ * is guaranteed to be the consistent.
+ */
+class AdapterHelper implements OpReorderer.Callback {
+
+    static final int POSITION_TYPE_INVISIBLE = 0;
+
+    static final int POSITION_TYPE_NEW_OR_LAID_OUT = 1;
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "AHT";
+
+    private Pools.Pool<UpdateOp> mUpdateOpPool = new Pools.SimplePool<UpdateOp>(UpdateOp.POOL_SIZE);
+
+    final ArrayList<UpdateOp> mPendingUpdates = new ArrayList<UpdateOp>();
+
+    final ArrayList<UpdateOp> mPostponedList = new ArrayList<UpdateOp>();
+
+    final Callback mCallback;
+
+    Runnable mOnItemProcessedCallback;
+
+    final boolean mDisableRecycler;
+
+    final OpReorderer mOpReorderer;
+
+    private int mExistingUpdateTypes = 0;
+
+    AdapterHelper(Callback callback) {
+        this(callback, false);
+    }
+
+    AdapterHelper(Callback callback, boolean disableRecycler) {
+        mCallback = callback;
+        mDisableRecycler = disableRecycler;
+        mOpReorderer = new OpReorderer(this);
+    }
+
+    AdapterHelper addUpdateOp(UpdateOp... ops) {
+        Collections.addAll(mPendingUpdates, ops);
+        return this;
+    }
+
+    void reset() {
+        recycleUpdateOpsAndClearList(mPendingUpdates);
+        recycleUpdateOpsAndClearList(mPostponedList);
+        mExistingUpdateTypes = 0;
+    }
+
+    void preProcess() {
+        mOpReorderer.reorderOps(mPendingUpdates);
+        final int count = mPendingUpdates.size();
+        for (int i = 0; i < count; i++) {
+            UpdateOp op = mPendingUpdates.get(i);
+            switch (op.cmd) {
+                case UpdateOp.ADD:
+                    applyAdd(op);
+                    break;
+                case UpdateOp.REMOVE:
+                    applyRemove(op);
+                    break;
+                case UpdateOp.UPDATE:
+                    applyUpdate(op);
+                    break;
+                case UpdateOp.MOVE:
+                    applyMove(op);
+                    break;
+            }
+            if (mOnItemProcessedCallback != null) {
+                mOnItemProcessedCallback.run();
+            }
+        }
+        mPendingUpdates.clear();
+    }
+
+    void consumePostponedUpdates() {
+        final int count = mPostponedList.size();
+        for (int i = 0; i < count; i++) {
+            mCallback.onDispatchSecondPass(mPostponedList.get(i));
+        }
+        recycleUpdateOpsAndClearList(mPostponedList);
+        mExistingUpdateTypes = 0;
+    }
+
+    private void applyMove(UpdateOp op) {
+        // MOVE ops are pre-processed so at this point, we know that item is still in the adapter.
+        // otherwise, it would be converted into a REMOVE operation
+        postponeAndUpdateViewHolders(op);
+    }
+
+    private void applyRemove(UpdateOp op) {
+        int tmpStart = op.positionStart;
+        int tmpCount = 0;
+        int tmpEnd = op.positionStart + op.itemCount;
+        int type = -1;
+        for (int position = op.positionStart; position < tmpEnd; position++) {
+            boolean typeChanged = false;
+            RecyclerView.ViewHolder vh = mCallback.findViewHolder(position);
+            if (vh != null || canFindInPreLayout(position)) {
+                // If a ViewHolder exists or this is a newly added item, we can defer this update
+                // to post layout stage.
+                // * For existing ViewHolders, we'll fake its existence in the pre-layout phase.
+                // * For items that are added and removed in the same process cycle, they won't
+                // have any effect in pre-layout since their add ops are already deferred to
+                // post-layout pass.
+                if (type == POSITION_TYPE_INVISIBLE) {
+                    // Looks like we have other updates that we cannot merge with this one.
+                    // Create an UpdateOp and dispatch it to LayoutManager.
+                    UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null);
+                    dispatchAndUpdateViewHolders(newOp);
+                    typeChanged = true;
+                }
+                type = POSITION_TYPE_NEW_OR_LAID_OUT;
+            } else {
+                // This update cannot be recovered because we don't have a ViewHolder representing
+                // this position. Instead, post it to LayoutManager immediately
+                if (type == POSITION_TYPE_NEW_OR_LAID_OUT) {
+                    // Looks like we have other updates that we cannot merge with this one.
+                    // Create UpdateOp op and dispatch it to LayoutManager.
+                    UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null);
+                    postponeAndUpdateViewHolders(newOp);
+                    typeChanged = true;
+                }
+                type = POSITION_TYPE_INVISIBLE;
+            }
+            if (typeChanged) {
+                position -= tmpCount; // also equal to tmpStart
+                tmpEnd -= tmpCount;
+                tmpCount = 1;
+            } else {
+                tmpCount++;
+            }
+        }
+        if (tmpCount != op.itemCount) { // all 1 effect
+            recycleUpdateOp(op);
+            op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null);
+        }
+        if (type == POSITION_TYPE_INVISIBLE) {
+            dispatchAndUpdateViewHolders(op);
+        } else {
+            postponeAndUpdateViewHolders(op);
+        }
+    }
+
+    private void applyUpdate(UpdateOp op) {
+        int tmpStart = op.positionStart;
+        int tmpCount = 0;
+        int tmpEnd = op.positionStart + op.itemCount;
+        int type = -1;
+        for (int position = op.positionStart; position < tmpEnd; position++) {
+            RecyclerView.ViewHolder vh = mCallback.findViewHolder(position);
+            if (vh != null || canFindInPreLayout(position)) { // deferred
+                if (type == POSITION_TYPE_INVISIBLE) {
+                    UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount,
+                            op.payload);
+                    dispatchAndUpdateViewHolders(newOp);
+                    tmpCount = 0;
+                    tmpStart = position;
+                }
+                type = POSITION_TYPE_NEW_OR_LAID_OUT;
+            } else { // applied
+                if (type == POSITION_TYPE_NEW_OR_LAID_OUT) {
+                    UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount,
+                            op.payload);
+                    postponeAndUpdateViewHolders(newOp);
+                    tmpCount = 0;
+                    tmpStart = position;
+                }
+                type = POSITION_TYPE_INVISIBLE;
+            }
+            tmpCount++;
+        }
+        if (tmpCount != op.itemCount) { // all 1 effect
+            Object payload = op.payload;
+            recycleUpdateOp(op);
+            op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, payload);
+        }
+        if (type == POSITION_TYPE_INVISIBLE) {
+            dispatchAndUpdateViewHolders(op);
+        } else {
+            postponeAndUpdateViewHolders(op);
+        }
+    }
+
+    private void dispatchAndUpdateViewHolders(UpdateOp op) {
+        // tricky part.
+        // traverse all postpones and revert their changes on this op if necessary, apply updated
+        // dispatch to them since now they are after this op.
+        if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) {
+            throw new IllegalArgumentException("should not dispatch add or move for pre layout");
+        }
+        if (DEBUG) {
+            Log.d(TAG, "dispatch (pre)" + op);
+            Log.d(TAG, "postponed state before:");
+            for (UpdateOp updateOp : mPostponedList) {
+                Log.d(TAG, updateOp.toString());
+            }
+            Log.d(TAG, "----");
+        }
+
+        // handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial
+        // TODO Since move ops are pushed to end, we should not need this anymore
+        int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd);
+        if (DEBUG) {
+            Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart);
+        }
+        int tmpCnt = 1;
+        int offsetPositionForPartial = op.positionStart;
+        final int positionMultiplier;
+        switch (op.cmd) {
+            case UpdateOp.UPDATE:
+                positionMultiplier = 1;
+                break;
+            case UpdateOp.REMOVE:
+                positionMultiplier = 0;
+                break;
+            default:
+                throw new IllegalArgumentException("op should be remove or update." + op);
+        }
+        for (int p = 1; p < op.itemCount; p++) {
+            final int pos = op.positionStart + (positionMultiplier * p);
+            int updatedPos = updatePositionWithPostponed(pos, op.cmd);
+            if (DEBUG) {
+                Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos);
+            }
+            boolean continuous = false;
+            switch (op.cmd) {
+                case UpdateOp.UPDATE:
+                    continuous = updatedPos == tmpStart + 1;
+                    break;
+                case UpdateOp.REMOVE:
+                    continuous = updatedPos == tmpStart;
+                    break;
+            }
+            if (continuous) {
+                tmpCnt++;
+            } else {
+                // need to dispatch this separately
+                UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, op.payload);
+                if (DEBUG) {
+                    Log.d(TAG, "need to dispatch separately " + tmp);
+                }
+                dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial);
+                recycleUpdateOp(tmp);
+                if (op.cmd == UpdateOp.UPDATE) {
+                    offsetPositionForPartial += tmpCnt;
+                }
+                tmpStart = updatedPos; // need to remove previously dispatched
+                tmpCnt = 1;
+            }
+        }
+        Object payload = op.payload;
+        recycleUpdateOp(op);
+        if (tmpCnt > 0) {
+            UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, payload);
+            if (DEBUG) {
+                Log.d(TAG, "dispatching:" + tmp);
+            }
+            dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial);
+            recycleUpdateOp(tmp);
+        }
+        if (DEBUG) {
+            Log.d(TAG, "post dispatch");
+            Log.d(TAG, "postponed state after:");
+            for (UpdateOp updateOp : mPostponedList) {
+                Log.d(TAG, updateOp.toString());
+            }
+            Log.d(TAG, "----");
+        }
+    }
+
+    void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) {
+        mCallback.onDispatchFirstPass(op);
+        switch (op.cmd) {
+            case UpdateOp.REMOVE:
+                mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount);
+                break;
+            case UpdateOp.UPDATE:
+                mCallback.markViewHoldersUpdated(offsetStart, op.itemCount, op.payload);
+                break;
+            default:
+                throw new IllegalArgumentException("only remove and update ops can be dispatched"
+                        + " in first pass");
+        }
+    }
+
+    private int updatePositionWithPostponed(int pos, int cmd) {
+        final int count = mPostponedList.size();
+        for (int i = count - 1; i >= 0; i--) {
+            UpdateOp postponed = mPostponedList.get(i);
+            if (postponed.cmd == UpdateOp.MOVE) {
+                int start, end;
+                if (postponed.positionStart < postponed.itemCount) {
+                    start = postponed.positionStart;
+                    end = postponed.itemCount;
+                } else {
+                    start = postponed.itemCount;
+                    end = postponed.positionStart;
+                }
+                if (pos >= start && pos <= end) {
+                    //i'm affected
+                    if (start == postponed.positionStart) {
+                        if (cmd == UpdateOp.ADD) {
+                            postponed.itemCount++;
+                        } else if (cmd == UpdateOp.REMOVE) {
+                            postponed.itemCount--;
+                        }
+                        // op moved to left, move it right to revert
+                        pos++;
+                    } else {
+                        if (cmd == UpdateOp.ADD) {
+                            postponed.positionStart++;
+                        } else if (cmd == UpdateOp.REMOVE) {
+                            postponed.positionStart--;
+                        }
+                        // op was moved right, move left to revert
+                        pos--;
+                    }
+                } else if (pos < postponed.positionStart) {
+                    // postponed MV is outside the dispatched OP. if it is before, offset
+                    if (cmd == UpdateOp.ADD) {
+                        postponed.positionStart++;
+                        postponed.itemCount++;
+                    } else if (cmd == UpdateOp.REMOVE) {
+                        postponed.positionStart--;
+                        postponed.itemCount--;
+                    }
+                }
+            } else {
+                if (postponed.positionStart <= pos) {
+                    if (postponed.cmd == UpdateOp.ADD) {
+                        pos -= postponed.itemCount;
+                    } else if (postponed.cmd == UpdateOp.REMOVE) {
+                        pos += postponed.itemCount;
+                    }
+                } else {
+                    if (cmd == UpdateOp.ADD) {
+                        postponed.positionStart++;
+                    } else if (cmd == UpdateOp.REMOVE) {
+                        postponed.positionStart--;
+                    }
+                }
+            }
+            if (DEBUG) {
+                Log.d(TAG, "dispath (step" + i + ")");
+                Log.d(TAG, "postponed state:" + i + ", pos:" + pos);
+                for (UpdateOp updateOp : mPostponedList) {
+                    Log.d(TAG, updateOp.toString());
+                }
+                Log.d(TAG, "----");
+            }
+        }
+        for (int i = mPostponedList.size() - 1; i >= 0; i--) {
+            UpdateOp op = mPostponedList.get(i);
+            if (op.cmd == UpdateOp.MOVE) {
+                if (op.itemCount == op.positionStart || op.itemCount < 0) {
+                    mPostponedList.remove(i);
+                    recycleUpdateOp(op);
+                }
+            } else if (op.itemCount <= 0) {
+                mPostponedList.remove(i);
+                recycleUpdateOp(op);
+            }
+        }
+        return pos;
+    }
+
+    private boolean canFindInPreLayout(int position) {
+        final int count = mPostponedList.size();
+        for (int i = 0; i < count; i++) {
+            UpdateOp op = mPostponedList.get(i);
+            if (op.cmd == UpdateOp.MOVE) {
+                if (findPositionOffset(op.itemCount, i + 1) == position) {
+                    return true;
+                }
+            } else if (op.cmd == UpdateOp.ADD) {
+                // TODO optimize.
+                final int end = op.positionStart + op.itemCount;
+                for (int pos = op.positionStart; pos < end; pos++) {
+                    if (findPositionOffset(pos, i + 1) == position) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    private void applyAdd(UpdateOp op) {
+        postponeAndUpdateViewHolders(op);
+    }
+
+    private void postponeAndUpdateViewHolders(UpdateOp op) {
+        if (DEBUG) {
+            Log.d(TAG, "postponing " + op);
+        }
+        mPostponedList.add(op);
+        switch (op.cmd) {
+            case UpdateOp.ADD:
+                mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount);
+                break;
+            case UpdateOp.MOVE:
+                mCallback.offsetPositionsForMove(op.positionStart, op.itemCount);
+                break;
+            case UpdateOp.REMOVE:
+                mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart,
+                        op.itemCount);
+                break;
+            case UpdateOp.UPDATE:
+                mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown update op type for " + op);
+        }
+    }
+
+    boolean hasPendingUpdates() {
+        return mPendingUpdates.size() > 0;
+    }
+
+    boolean hasAnyUpdateTypes(int updateTypes) {
+        return (mExistingUpdateTypes & updateTypes) != 0;
+    }
+
+    int findPositionOffset(int position) {
+        return findPositionOffset(position, 0);
+    }
+
+    int findPositionOffset(int position, int firstPostponedItem) {
+        int count = mPostponedList.size();
+        for (int i = firstPostponedItem; i < count; ++i) {
+            UpdateOp op = mPostponedList.get(i);
+            if (op.cmd == UpdateOp.MOVE) {
+                if (op.positionStart == position) {
+                    position = op.itemCount;
+                } else {
+                    if (op.positionStart < position) {
+                        position--; // like a remove
+                    }
+                    if (op.itemCount <= position) {
+                        position++; // like an add
+                    }
+                }
+            } else if (op.positionStart <= position) {
+                if (op.cmd == UpdateOp.REMOVE) {
+                    if (position < op.positionStart + op.itemCount) {
+                        return -1;
+                    }
+                    position -= op.itemCount;
+                } else if (op.cmd == UpdateOp.ADD) {
+                    position += op.itemCount;
+                }
+            }
+        }
+        return position;
+    }
+
+    /**
+     * @return True if updates should be processed.
+     */
+    boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+        if (itemCount < 1) {
+            return false;
+        }
+        mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload));
+        mExistingUpdateTypes |= UpdateOp.UPDATE;
+        return mPendingUpdates.size() == 1;
+    }
+
+    /**
+     * @return True if updates should be processed.
+     */
+    boolean onItemRangeInserted(int positionStart, int itemCount) {
+        if (itemCount < 1) {
+            return false;
+        }
+        mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null));
+        mExistingUpdateTypes |= UpdateOp.ADD;
+        return mPendingUpdates.size() == 1;
+    }
+
+    /**
+     * @return True if updates should be processed.
+     */
+    boolean onItemRangeRemoved(int positionStart, int itemCount) {
+        if (itemCount < 1) {
+            return false;
+        }
+        mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null));
+        mExistingUpdateTypes |= UpdateOp.REMOVE;
+        return mPendingUpdates.size() == 1;
+    }
+
+    /**
+     * @return True if updates should be processed.
+     */
+    boolean onItemRangeMoved(int from, int to, int itemCount) {
+        if (from == to) {
+            return false; // no-op
+        }
+        if (itemCount != 1) {
+            throw new IllegalArgumentException("Moving more than 1 item is not supported yet");
+        }
+        mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null));
+        mExistingUpdateTypes |= UpdateOp.MOVE;
+        return mPendingUpdates.size() == 1;
+    }
+
+    /**
+     * Skips pre-processing and applies all updates in one pass.
+     */
+    void consumeUpdatesInOnePass() {
+        // we still consume postponed updates (if there is) in case there was a pre-process call
+        // w/o a matching consumePostponedUpdates.
+        consumePostponedUpdates();
+        final int count = mPendingUpdates.size();
+        for (int i = 0; i < count; i++) {
+            UpdateOp op = mPendingUpdates.get(i);
+            switch (op.cmd) {
+                case UpdateOp.ADD:
+                    mCallback.onDispatchSecondPass(op);
+                    mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount);
+                    break;
+                case UpdateOp.REMOVE:
+                    mCallback.onDispatchSecondPass(op);
+                    mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount);
+                    break;
+                case UpdateOp.UPDATE:
+                    mCallback.onDispatchSecondPass(op);
+                    mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload);
+                    break;
+                case UpdateOp.MOVE:
+                    mCallback.onDispatchSecondPass(op);
+                    mCallback.offsetPositionsForMove(op.positionStart, op.itemCount);
+                    break;
+            }
+            if (mOnItemProcessedCallback != null) {
+                mOnItemProcessedCallback.run();
+            }
+        }
+        recycleUpdateOpsAndClearList(mPendingUpdates);
+        mExistingUpdateTypes = 0;
+    }
+
+    public int applyPendingUpdatesToPosition(int position) {
+        final int size = mPendingUpdates.size();
+        for (int i = 0; i < size; i++) {
+            UpdateOp op = mPendingUpdates.get(i);
+            switch (op.cmd) {
+                case UpdateOp.ADD:
+                    if (op.positionStart <= position) {
+                        position += op.itemCount;
+                    }
+                    break;
+                case UpdateOp.REMOVE:
+                    if (op.positionStart <= position) {
+                        final int end = op.positionStart + op.itemCount;
+                        if (end > position) {
+                            return RecyclerView.NO_POSITION;
+                        }
+                        position -= op.itemCount;
+                    }
+                    break;
+                case UpdateOp.MOVE:
+                    if (op.positionStart == position) {
+                        position = op.itemCount; //position end
+                    } else {
+                        if (op.positionStart < position) {
+                            position -= 1;
+                        }
+                        if (op.itemCount <= position) {
+                            position += 1;
+                        }
+                    }
+                    break;
+            }
+        }
+        return position;
+    }
+
+    boolean hasUpdates() {
+        return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty();
+    }
+
+    /**
+     * Queued operation to happen when child views are updated.
+     */
+    static class UpdateOp {
+
+        static final int ADD = 1;
+
+        static final int REMOVE = 1 << 1;
+
+        static final int UPDATE = 1 << 2;
+
+        static final int MOVE = 1 << 3;
+
+        static final int POOL_SIZE = 30;
+
+        int cmd;
+
+        int positionStart;
+
+        Object payload;
+
+        // holds the target position if this is a MOVE
+        int itemCount;
+
+        UpdateOp(int cmd, int positionStart, int itemCount, Object payload) {
+            this.cmd = cmd;
+            this.positionStart = positionStart;
+            this.itemCount = itemCount;
+            this.payload = payload;
+        }
+
+        String cmdToString() {
+            switch (cmd) {
+                case ADD:
+                    return "add";
+                case REMOVE:
+                    return "rm";
+                case UPDATE:
+                    return "up";
+                case MOVE:
+                    return "mv";
+            }
+            return "??";
+        }
+
+        @Override
+        public String toString() {
+            return Integer.toHexString(System.identityHashCode(this))
+                    + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount
+                    + ",p:" + payload + "]";
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            UpdateOp op = (UpdateOp) o;
+
+            if (cmd != op.cmd) {
+                return false;
+            }
+            if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) {
+                // reverse of this is also true
+                if (itemCount == op.positionStart && positionStart == op.itemCount) {
+                    return true;
+                }
+            }
+            if (itemCount != op.itemCount) {
+                return false;
+            }
+            if (positionStart != op.positionStart) {
+                return false;
+            }
+            if (payload != null) {
+                if (!payload.equals(op.payload)) {
+                    return false;
+                }
+            } else if (op.payload != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = cmd;
+            result = 31 * result + positionStart;
+            result = 31 * result + itemCount;
+            return result;
+        }
+    }
+
+    @Override
+    public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount, Object payload) {
+        UpdateOp op = mUpdateOpPool.acquire();
+        if (op == null) {
+            op = new UpdateOp(cmd, positionStart, itemCount, payload);
+        } else {
+            op.cmd = cmd;
+            op.positionStart = positionStart;
+            op.itemCount = itemCount;
+            op.payload = payload;
+        }
+        return op;
+    }
+
+    @Override
+    public void recycleUpdateOp(UpdateOp op) {
+        if (!mDisableRecycler) {
+            op.payload = null;
+            mUpdateOpPool.release(op);
+        }
+    }
+
+    void recycleUpdateOpsAndClearList(List<UpdateOp> ops) {
+        final int count = ops.size();
+        for (int i = 0; i < count; i++) {
+            recycleUpdateOp(ops.get(i));
+        }
+        ops.clear();
+    }
+
+    /**
+     * Contract between AdapterHelper and RecyclerView.
+     */
+    interface Callback {
+
+        RecyclerView.ViewHolder findViewHolder(int position);
+
+        void offsetPositionsForRemovingInvisible(int positionStart, int itemCount);
+
+        void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount);
+
+        void markViewHoldersUpdated(int positionStart, int itemCount, Object payloads);
+
+        void onDispatchFirstPass(UpdateOp updateOp);
+
+        void onDispatchSecondPass(UpdateOp updateOp);
+
+        void offsetPositionsForAdd(int positionStart, int itemCount);
+
+        void offsetPositionsForMove(int from, int to);
+    }
+}
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 20230cd..b172dbc 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -187,6 +187,7 @@
     }
 
     @Override
+    @RemotableViewMethod
     public void setVisibility(int visibility) {
         mDesiredVisibility = visibility;
         updateVisibility();
diff --git a/core/java/com/android/internal/widget/ChildHelper.java b/core/java/com/android/internal/widget/ChildHelper.java
new file mode 100644
index 0000000..e9136d0
--- /dev/null
+++ b/core/java/com/android/internal/widget/ChildHelper.java
@@ -0,0 +1,538 @@
+/*
+ * 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.widget;
+
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class to manage children.
+ * <p>
+ * It wraps a RecyclerView and adds ability to hide some children. There are two sets of methods
+ * provided by this class. <b>Regular</b> methods are the ones that replicate ViewGroup methods
+ * like getChildAt, getChildCount etc. These methods ignore hidden children.
+ * <p>
+ * When RecyclerView needs direct access to the view group children, it can call unfiltered
+ * methods like get getUnfilteredChildCount or getUnfilteredChildAt.
+ */
+class ChildHelper {
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "ChildrenHelper";
+
+    final Callback mCallback;
+
+    final Bucket mBucket;
+
+    final List<View> mHiddenViews;
+
+    ChildHelper(Callback callback) {
+        mCallback = callback;
+        mBucket = new Bucket();
+        mHiddenViews = new ArrayList<View>();
+    }
+
+    /**
+     * Marks a child view as hidden
+     *
+     * @param child  View to hide.
+     */
+    private void hideViewInternal(View child) {
+        mHiddenViews.add(child);
+        mCallback.onEnteredHiddenState(child);
+    }
+
+    /**
+     * Unmarks a child view as hidden.
+     *
+     * @param child  View to hide.
+     */
+    private boolean unhideViewInternal(View child) {
+        if (mHiddenViews.remove(child)) {
+            mCallback.onLeftHiddenState(child);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Adds a view to the ViewGroup
+     *
+     * @param child  View to add.
+     * @param hidden If set to true, this item will be invisible from regular methods.
+     */
+    void addView(View child, boolean hidden) {
+        addView(child, -1, hidden);
+    }
+
+    /**
+     * Add a view to the ViewGroup at an index
+     *
+     * @param child  View to add.
+     * @param index  Index of the child from the regular perspective (excluding hidden views).
+     *               ChildHelper offsets this index to actual ViewGroup index.
+     * @param hidden If set to true, this item will be invisible from regular methods.
+     */
+    void addView(View child, int index, boolean hidden) {
+        final int offset;
+        if (index < 0) {
+            offset = mCallback.getChildCount();
+        } else {
+            offset = getOffset(index);
+        }
+        mBucket.insert(offset, hidden);
+        if (hidden) {
+            hideViewInternal(child);
+        }
+        mCallback.addView(child, offset);
+        if (DEBUG) {
+            Log.d(TAG, "addViewAt " + index + ",h:" + hidden + ", " + this);
+        }
+    }
+
+    private int getOffset(int index) {
+        if (index < 0) {
+            return -1; //anything below 0 won't work as diff will be undefined.
+        }
+        final int limit = mCallback.getChildCount();
+        int offset = index;
+        while (offset < limit) {
+            final int removedBefore = mBucket.countOnesBefore(offset);
+            final int diff = index - (offset - removedBefore);
+            if (diff == 0) {
+                while (mBucket.get(offset)) { // ensure this offset is not hidden
+                    offset++;
+                }
+                return offset;
+            } else {
+                offset += diff;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the provided View from underlying RecyclerView.
+     *
+     * @param view The view to remove.
+     */
+    void removeView(View view) {
+        int index = mCallback.indexOfChild(view);
+        if (index < 0) {
+            return;
+        }
+        if (mBucket.remove(index)) {
+            unhideViewInternal(view);
+        }
+        mCallback.removeViewAt(index);
+        if (DEBUG) {
+            Log.d(TAG, "remove View off:" + index + "," + this);
+        }
+    }
+
+    /**
+     * Removes the view at the provided index from RecyclerView.
+     *
+     * @param index Index of the child from the regular perspective (excluding hidden views).
+     *              ChildHelper offsets this index to actual ViewGroup index.
+     */
+    void removeViewAt(int index) {
+        final int offset = getOffset(index);
+        final View view = mCallback.getChildAt(offset);
+        if (view == null) {
+            return;
+        }
+        if (mBucket.remove(offset)) {
+            unhideViewInternal(view);
+        }
+        mCallback.removeViewAt(offset);
+        if (DEBUG) {
+            Log.d(TAG, "removeViewAt " + index + ", off:" + offset + ", " + this);
+        }
+    }
+
+    /**
+     * Returns the child at provided index.
+     *
+     * @param index Index of the child to return in regular perspective.
+     */
+    View getChildAt(int index) {
+        final int offset = getOffset(index);
+        return mCallback.getChildAt(offset);
+    }
+
+    /**
+     * Removes all views from the ViewGroup including the hidden ones.
+     */
+    void removeAllViewsUnfiltered() {
+        mBucket.reset();
+        for (int i = mHiddenViews.size() - 1; i >= 0; i--) {
+            mCallback.onLeftHiddenState(mHiddenViews.get(i));
+            mHiddenViews.remove(i);
+        }
+        mCallback.removeAllViews();
+        if (DEBUG) {
+            Log.d(TAG, "removeAllViewsUnfiltered");
+        }
+    }
+
+    /**
+     * This can be used to find a disappearing view by position.
+     *
+     * @param position The adapter position of the item.
+     * @return         A hidden view with a valid ViewHolder that matches the position.
+     */
+    View findHiddenNonRemovedView(int position) {
+        final int count = mHiddenViews.size();
+        for (int i = 0; i < count; i++) {
+            final View view = mHiddenViews.get(i);
+            RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view);
+            if (holder.getLayoutPosition() == position
+                    && !holder.isInvalid()
+                    && !holder.isRemoved()) {
+                return view;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Attaches the provided view to the underlying ViewGroup.
+     *
+     * @param child        Child to attach.
+     * @param index        Index of the child to attach in regular perspective.
+     * @param layoutParams LayoutParams for the child.
+     * @param hidden       If set to true, this item will be invisible to the regular methods.
+     */
+    void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams,
+            boolean hidden) {
+        final int offset;
+        if (index < 0) {
+            offset = mCallback.getChildCount();
+        } else {
+            offset = getOffset(index);
+        }
+        mBucket.insert(offset, hidden);
+        if (hidden) {
+            hideViewInternal(child);
+        }
+        mCallback.attachViewToParent(child, offset, layoutParams);
+        if (DEBUG) {
+            Log.d(TAG, "attach view to parent index:" + index + ",off:" + offset + ","
+                    + "h:" + hidden + ", " + this);
+        }
+    }
+
+    /**
+     * Returns the number of children that are not hidden.
+     *
+     * @return Number of children that are not hidden.
+     * @see #getChildAt(int)
+     */
+    int getChildCount() {
+        return mCallback.getChildCount() - mHiddenViews.size();
+    }
+
+    /**
+     * Returns the total number of children.
+     *
+     * @return The total number of children including the hidden views.
+     * @see #getUnfilteredChildAt(int)
+     */
+    int getUnfilteredChildCount() {
+        return mCallback.getChildCount();
+    }
+
+    /**
+     * Returns a child by ViewGroup offset. ChildHelper won't offset this index.
+     *
+     * @param index ViewGroup index of the child to return.
+     * @return The view in the provided index.
+     */
+    View getUnfilteredChildAt(int index) {
+        return mCallback.getChildAt(index);
+    }
+
+    /**
+     * Detaches the view at the provided index.
+     *
+     * @param index Index of the child to return in regular perspective.
+     */
+    void detachViewFromParent(int index) {
+        final int offset = getOffset(index);
+        mBucket.remove(offset);
+        mCallback.detachViewFromParent(offset);
+        if (DEBUG) {
+            Log.d(TAG, "detach view from parent " + index + ", off:" + offset);
+        }
+    }
+
+    /**
+     * Returns the index of the child in regular perspective.
+     *
+     * @param child The child whose index will be returned.
+     * @return The regular perspective index of the child or -1 if it does not exists.
+     */
+    int indexOfChild(View child) {
+        final int index = mCallback.indexOfChild(child);
+        if (index == -1) {
+            return -1;
+        }
+        if (mBucket.get(index)) {
+            if (DEBUG) {
+                throw new IllegalArgumentException("cannot get index of a hidden child");
+            } else {
+                return -1;
+            }
+        }
+        // reverse the index
+        return index - mBucket.countOnesBefore(index);
+    }
+
+    /**
+     * Returns whether a View is visible to LayoutManager or not.
+     *
+     * @param view The child view to check. Should be a child of the Callback.
+     * @return True if the View is not visible to LayoutManager
+     */
+    boolean isHidden(View view) {
+        return mHiddenViews.contains(view);
+    }
+
+    /**
+     * Marks a child view as hidden.
+     *
+     * @param view The view to hide.
+     */
+    void hide(View view) {
+        final int offset = mCallback.indexOfChild(view);
+        if (offset < 0) {
+            throw new IllegalArgumentException("view is not a child, cannot hide " + view);
+        }
+        if (DEBUG && mBucket.get(offset)) {
+            throw new RuntimeException("trying to hide same view twice, how come ? " + view);
+        }
+        mBucket.set(offset);
+        hideViewInternal(view);
+        if (DEBUG) {
+            Log.d(TAG, "hiding child " + view + " at offset " + offset + ", " + this);
+        }
+    }
+
+    /**
+     * Moves a child view from hidden list to regular list.
+     * Calling this method should probably be followed by a detach, otherwise, it will suddenly
+     * show up in LayoutManager's children list.
+     *
+     * @param view The hidden View to unhide
+     */
+    void unhide(View view) {
+        final int offset = mCallback.indexOfChild(view);
+        if (offset < 0) {
+            throw new IllegalArgumentException("view is not a child, cannot hide " + view);
+        }
+        if (!mBucket.get(offset)) {
+            throw new RuntimeException("trying to unhide a view that was not hidden" + view);
+        }
+        mBucket.clear(offset);
+        unhideViewInternal(view);
+    }
+
+    @Override
+    public String toString() {
+        return mBucket.toString() + ", hidden list:" + mHiddenViews.size();
+    }
+
+    /**
+     * Removes a view from the ViewGroup if it is hidden.
+     *
+     * @param view The view to remove.
+     * @return True if the View is found and it is hidden. False otherwise.
+     */
+    boolean removeViewIfHidden(View view) {
+        final int index = mCallback.indexOfChild(view);
+        if (index == -1) {
+            if (unhideViewInternal(view) && DEBUG) {
+                throw new IllegalStateException("view is in hidden list but not in view group");
+            }
+            return true;
+        }
+        if (mBucket.get(index)) {
+            mBucket.remove(index);
+            if (!unhideViewInternal(view) && DEBUG) {
+                throw new IllegalStateException(
+                        "removed a hidden view but it is not in hidden views list");
+            }
+            mCallback.removeViewAt(index);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Bitset implementation that provides methods to offset indices.
+     */
+    static class Bucket {
+
+        static final int BITS_PER_WORD = Long.SIZE;
+
+        static final long LAST_BIT = 1L << (Long.SIZE - 1);
+
+        long mData = 0;
+
+        Bucket mNext;
+
+        void set(int index) {
+            if (index >= BITS_PER_WORD) {
+                ensureNext();
+                mNext.set(index - BITS_PER_WORD);
+            } else {
+                mData |= 1L << index;
+            }
+        }
+
+        private void ensureNext() {
+            if (mNext == null) {
+                mNext = new Bucket();
+            }
+        }
+
+        void clear(int index) {
+            if (index >= BITS_PER_WORD) {
+                if (mNext != null) {
+                    mNext.clear(index - BITS_PER_WORD);
+                }
+            } else {
+                mData &= ~(1L << index);
+            }
+
+        }
+
+        boolean get(int index) {
+            if (index >= BITS_PER_WORD) {
+                ensureNext();
+                return mNext.get(index - BITS_PER_WORD);
+            } else {
+                return (mData & (1L << index)) != 0;
+            }
+        }
+
+        void reset() {
+            mData = 0;
+            if (mNext != null) {
+                mNext.reset();
+            }
+        }
+
+        void insert(int index, boolean value) {
+            if (index >= BITS_PER_WORD) {
+                ensureNext();
+                mNext.insert(index - BITS_PER_WORD, value);
+            } else {
+                final boolean lastBit = (mData & LAST_BIT) != 0;
+                long mask = (1L << index) - 1;
+                final long before = mData & mask;
+                final long after = ((mData & ~mask)) << 1;
+                mData = before | after;
+                if (value) {
+                    set(index);
+                } else {
+                    clear(index);
+                }
+                if (lastBit || mNext != null) {
+                    ensureNext();
+                    mNext.insert(0, lastBit);
+                }
+            }
+        }
+
+        boolean remove(int index) {
+            if (index >= BITS_PER_WORD) {
+                ensureNext();
+                return mNext.remove(index - BITS_PER_WORD);
+            } else {
+                long mask = (1L << index);
+                final boolean value = (mData & mask) != 0;
+                mData &= ~mask;
+                mask = mask - 1;
+                final long before = mData & mask;
+                // cannot use >> because it adds one.
+                final long after = Long.rotateRight(mData & ~mask, 1);
+                mData = before | after;
+                if (mNext != null) {
+                    if (mNext.get(0)) {
+                        set(BITS_PER_WORD - 1);
+                    }
+                    mNext.remove(0);
+                }
+                return value;
+            }
+        }
+
+        int countOnesBefore(int index) {
+            if (mNext == null) {
+                if (index >= BITS_PER_WORD) {
+                    return Long.bitCount(mData);
+                }
+                return Long.bitCount(mData & ((1L << index) - 1));
+            }
+            if (index < BITS_PER_WORD) {
+                return Long.bitCount(mData & ((1L << index) - 1));
+            } else {
+                return mNext.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return mNext == null ? Long.toBinaryString(mData)
+                    : mNext.toString() + "xx" + Long.toBinaryString(mData);
+        }
+    }
+
+    interface Callback {
+
+        int getChildCount();
+
+        void addView(View child, int index);
+
+        int indexOfChild(View view);
+
+        void removeViewAt(int index);
+
+        View getChildAt(int offset);
+
+        void removeAllViews();
+
+        RecyclerView.ViewHolder getChildViewHolder(View view);
+
+        void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams);
+
+        void detachViewFromParent(int offset);
+
+        void onEnteredHiddenState(View child);
+
+        void onLeftHiddenState(View child);
+    }
+}
+
diff --git a/core/java/com/android/internal/widget/DefaultItemAnimator.java b/core/java/com/android/internal/widget/DefaultItemAnimator.java
new file mode 100644
index 0000000..92345af
--- /dev/null
+++ b/core/java/com/android/internal/widget/DefaultItemAnimator.java
@@ -0,0 +1,668 @@
+/*
+ * 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.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+
+import com.android.internal.widget.RecyclerView.ViewHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This implementation of {@link RecyclerView.ItemAnimator} provides basic
+ * animations on remove, add, and move events that happen to the items in
+ * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
+ *
+ * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
+ */
+public class DefaultItemAnimator extends SimpleItemAnimator {
+    private static final boolean DEBUG = false;
+
+    private static TimeInterpolator sDefaultInterpolator;
+
+    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<>();
+    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<>();
+    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
+    private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
+
+    ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList<>();
+    ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
+    ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
+
+    ArrayList<ViewHolder> mAddAnimations = new ArrayList<>();
+    ArrayList<ViewHolder> mMoveAnimations = new ArrayList<>();
+    ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<>();
+    ArrayList<ViewHolder> mChangeAnimations = new ArrayList<>();
+
+    private static class MoveInfo {
+        public ViewHolder holder;
+        public int fromX, fromY, toX, toY;
+
+        MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
+            this.holder = holder;
+            this.fromX = fromX;
+            this.fromY = fromY;
+            this.toX = toX;
+            this.toY = toY;
+        }
+    }
+
+    private static class ChangeInfo {
+        public ViewHolder oldHolder, newHolder;
+        public int fromX, fromY, toX, toY;
+        private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
+            this.oldHolder = oldHolder;
+            this.newHolder = newHolder;
+        }
+
+        ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder,
+                int fromX, int fromY, int toX, int toY) {
+            this(oldHolder, newHolder);
+            this.fromX = fromX;
+            this.fromY = fromY;
+            this.toX = toX;
+            this.toY = toY;
+        }
+
+        @Override
+        public String toString() {
+            return "ChangeInfo{"
+                    + "oldHolder=" + oldHolder
+                    + ", newHolder=" + newHolder
+                    + ", fromX=" + fromX
+                    + ", fromY=" + fromY
+                    + ", toX=" + toX
+                    + ", toY=" + toY
+                    + '}';
+        }
+    }
+
+    @Override
+    public void runPendingAnimations() {
+        boolean removalsPending = !mPendingRemovals.isEmpty();
+        boolean movesPending = !mPendingMoves.isEmpty();
+        boolean changesPending = !mPendingChanges.isEmpty();
+        boolean additionsPending = !mPendingAdditions.isEmpty();
+        if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
+            // nothing to animate
+            return;
+        }
+        // First, remove stuff
+        for (ViewHolder holder : mPendingRemovals) {
+            animateRemoveImpl(holder);
+        }
+        mPendingRemovals.clear();
+        // Next, move stuff
+        if (movesPending) {
+            final ArrayList<MoveInfo> moves = new ArrayList<>();
+            moves.addAll(mPendingMoves);
+            mMovesList.add(moves);
+            mPendingMoves.clear();
+            Runnable mover = new Runnable() {
+                @Override
+                public void run() {
+                    for (MoveInfo moveInfo : moves) {
+                        animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
+                                moveInfo.toX, moveInfo.toY);
+                    }
+                    moves.clear();
+                    mMovesList.remove(moves);
+                }
+            };
+            if (removalsPending) {
+                View view = moves.get(0).holder.itemView;
+                view.postOnAnimationDelayed(mover, getRemoveDuration());
+            } else {
+                mover.run();
+            }
+        }
+        // Next, change stuff, to run in parallel with move animations
+        if (changesPending) {
+            final ArrayList<ChangeInfo> changes = new ArrayList<>();
+            changes.addAll(mPendingChanges);
+            mChangesList.add(changes);
+            mPendingChanges.clear();
+            Runnable changer = new Runnable() {
+                @Override
+                public void run() {
+                    for (ChangeInfo change : changes) {
+                        animateChangeImpl(change);
+                    }
+                    changes.clear();
+                    mChangesList.remove(changes);
+                }
+            };
+            if (removalsPending) {
+                ViewHolder holder = changes.get(0).oldHolder;
+                holder.itemView.postOnAnimationDelayed(changer, getRemoveDuration());
+            } else {
+                changer.run();
+            }
+        }
+        // Next, add stuff
+        if (additionsPending) {
+            final ArrayList<ViewHolder> additions = new ArrayList<>();
+            additions.addAll(mPendingAdditions);
+            mAdditionsList.add(additions);
+            mPendingAdditions.clear();
+            Runnable adder = new Runnable() {
+                @Override
+                public void run() {
+                    for (ViewHolder holder : additions) {
+                        animateAddImpl(holder);
+                    }
+                    additions.clear();
+                    mAdditionsList.remove(additions);
+                }
+            };
+            if (removalsPending || movesPending || changesPending) {
+                long removeDuration = removalsPending ? getRemoveDuration() : 0;
+                long moveDuration = movesPending ? getMoveDuration() : 0;
+                long changeDuration = changesPending ? getChangeDuration() : 0;
+                long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
+                View view = additions.get(0).itemView;
+                view.postOnAnimationDelayed(adder, totalDelay);
+            } else {
+                adder.run();
+            }
+        }
+    }
+
+    @Override
+    public boolean animateRemove(final ViewHolder holder) {
+        resetAnimation(holder);
+        mPendingRemovals.add(holder);
+        return true;
+    }
+
+    private void animateRemoveImpl(final ViewHolder holder) {
+        final View view = holder.itemView;
+        final ViewPropertyAnimator animation = view.animate();
+        mRemoveAnimations.add(holder);
+        animation.setDuration(getRemoveDuration()).alpha(0).setListener(
+                new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animator) {
+                        dispatchRemoveStarting(holder);
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animator) {
+                        animation.setListener(null);
+                        view.setAlpha(1);
+                        dispatchRemoveFinished(holder);
+                        mRemoveAnimations.remove(holder);
+                        dispatchFinishedWhenDone();
+                    }
+                }).start();
+    }
+
+    @Override
+    public boolean animateAdd(final ViewHolder holder) {
+        resetAnimation(holder);
+        holder.itemView.setAlpha(0);
+        mPendingAdditions.add(holder);
+        return true;
+    }
+
+    void animateAddImpl(final ViewHolder holder) {
+        final View view = holder.itemView;
+        final ViewPropertyAnimator animation = view.animate();
+        mAddAnimations.add(holder);
+        animation.alpha(1).setDuration(getAddDuration())
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animator) {
+                        dispatchAddStarting(holder);
+                    }
+
+                    @Override
+                    public void onAnimationCancel(Animator animator) {
+                        view.setAlpha(1);
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animator) {
+                        animation.setListener(null);
+                        dispatchAddFinished(holder);
+                        mAddAnimations.remove(holder);
+                        dispatchFinishedWhenDone();
+                    }
+                }).start();
+    }
+
+    @Override
+    public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
+            int toX, int toY) {
+        final View view = holder.itemView;
+        fromX += holder.itemView.getTranslationX();
+        fromY += holder.itemView.getTranslationY();
+        resetAnimation(holder);
+        int deltaX = toX - fromX;
+        int deltaY = toY - fromY;
+        if (deltaX == 0 && deltaY == 0) {
+            dispatchMoveFinished(holder);
+            return false;
+        }
+        if (deltaX != 0) {
+            view.setTranslationX(-deltaX);
+        }
+        if (deltaY != 0) {
+            view.setTranslationY(-deltaY);
+        }
+        mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
+        return true;
+    }
+
+    void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
+        final View view = holder.itemView;
+        final int deltaX = toX - fromX;
+        final int deltaY = toY - fromY;
+        if (deltaX != 0) {
+            view.animate().translationX(0);
+        }
+        if (deltaY != 0) {
+            view.animate().translationY(0);
+        }
+        // TODO: make EndActions end listeners instead, since end actions aren't called when
+        // vpas are canceled (and can't end them. why?)
+        // need listener functionality in VPACompat for this. Ick.
+        final ViewPropertyAnimator animation = view.animate();
+        mMoveAnimations.add(holder);
+        animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animator) {
+                dispatchMoveStarting(holder);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animator) {
+                if (deltaX != 0) {
+                    view.setTranslationX(0);
+                }
+                if (deltaY != 0) {
+                    view.setTranslationY(0);
+                }
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animator) {
+                animation.setListener(null);
+                dispatchMoveFinished(holder);
+                mMoveAnimations.remove(holder);
+                dispatchFinishedWhenDone();
+            }
+        }).start();
+    }
+
+    @Override
+    public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
+            int fromX, int fromY, int toX, int toY) {
+        if (oldHolder == newHolder) {
+            // Don't know how to run change animations when the same view holder is re-used.
+            // run a move animation to handle position changes.
+            return animateMove(oldHolder, fromX, fromY, toX, toY);
+        }
+        final float prevTranslationX = oldHolder.itemView.getTranslationX();
+        final float prevTranslationY = oldHolder.itemView.getTranslationY();
+        final float prevAlpha = oldHolder.itemView.getAlpha();
+        resetAnimation(oldHolder);
+        int deltaX = (int) (toX - fromX - prevTranslationX);
+        int deltaY = (int) (toY - fromY - prevTranslationY);
+        // recover prev translation state after ending animation
+        oldHolder.itemView.setTranslationX(prevTranslationX);
+        oldHolder.itemView.setTranslationY(prevTranslationY);
+        oldHolder.itemView.setAlpha(prevAlpha);
+        if (newHolder != null) {
+            // carry over translation values
+            resetAnimation(newHolder);
+            newHolder.itemView.setTranslationX(-deltaX);
+            newHolder.itemView.setTranslationY(-deltaY);
+            newHolder.itemView.setAlpha(0);
+        }
+        mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
+        return true;
+    }
+
+    void animateChangeImpl(final ChangeInfo changeInfo) {
+        final ViewHolder holder = changeInfo.oldHolder;
+        final View view = holder == null ? null : holder.itemView;
+        final ViewHolder newHolder = changeInfo.newHolder;
+        final View newView = newHolder != null ? newHolder.itemView : null;
+        if (view != null) {
+            final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(
+                    getChangeDuration());
+            mChangeAnimations.add(changeInfo.oldHolder);
+            oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
+            oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
+            oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animator) {
+                    dispatchChangeStarting(changeInfo.oldHolder, true);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    oldViewAnim.setListener(null);
+                    view.setAlpha(1);
+                    view.setTranslationX(0);
+                    view.setTranslationY(0);
+                    dispatchChangeFinished(changeInfo.oldHolder, true);
+                    mChangeAnimations.remove(changeInfo.oldHolder);
+                    dispatchFinishedWhenDone();
+                }
+            }).start();
+        }
+        if (newView != null) {
+            final ViewPropertyAnimator newViewAnimation = newView.animate();
+            mChangeAnimations.add(changeInfo.newHolder);
+            newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration())
+                    .alpha(1).setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animator) {
+                            dispatchChangeStarting(changeInfo.newHolder, false);
+                        }
+                        @Override
+                        public void onAnimationEnd(Animator animator) {
+                            newViewAnimation.setListener(null);
+                            newView.setAlpha(1);
+                            newView.setTranslationX(0);
+                            newView.setTranslationY(0);
+                            dispatchChangeFinished(changeInfo.newHolder, false);
+                            mChangeAnimations.remove(changeInfo.newHolder);
+                            dispatchFinishedWhenDone();
+                        }
+                    }).start();
+        }
+    }
+
+    private void endChangeAnimation(List<ChangeInfo> infoList, ViewHolder item) {
+        for (int i = infoList.size() - 1; i >= 0; i--) {
+            ChangeInfo changeInfo = infoList.get(i);
+            if (endChangeAnimationIfNecessary(changeInfo, item)) {
+                if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
+                    infoList.remove(changeInfo);
+                }
+            }
+        }
+    }
+
+    private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
+        if (changeInfo.oldHolder != null) {
+            endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
+        }
+        if (changeInfo.newHolder != null) {
+            endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
+        }
+    }
+    private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
+        boolean oldItem = false;
+        if (changeInfo.newHolder == item) {
+            changeInfo.newHolder = null;
+        } else if (changeInfo.oldHolder == item) {
+            changeInfo.oldHolder = null;
+            oldItem = true;
+        } else {
+            return false;
+        }
+        item.itemView.setAlpha(1);
+        item.itemView.setTranslationX(0);
+        item.itemView.setTranslationY(0);
+        dispatchChangeFinished(item, oldItem);
+        return true;
+    }
+
+    @Override
+    public void endAnimation(ViewHolder item) {
+        final View view = item.itemView;
+        // this will trigger end callback which should set properties to their target values.
+        view.animate().cancel();
+        // TODO if some other animations are chained to end, how do we cancel them as well?
+        for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
+            MoveInfo moveInfo = mPendingMoves.get(i);
+            if (moveInfo.holder == item) {
+                view.setTranslationY(0);
+                view.setTranslationX(0);
+                dispatchMoveFinished(item);
+                mPendingMoves.remove(i);
+            }
+        }
+        endChangeAnimation(mPendingChanges, item);
+        if (mPendingRemovals.remove(item)) {
+            view.setAlpha(1);
+            dispatchRemoveFinished(item);
+        }
+        if (mPendingAdditions.remove(item)) {
+            view.setAlpha(1);
+            dispatchAddFinished(item);
+        }
+
+        for (int i = mChangesList.size() - 1; i >= 0; i--) {
+            ArrayList<ChangeInfo> changes = mChangesList.get(i);
+            endChangeAnimation(changes, item);
+            if (changes.isEmpty()) {
+                mChangesList.remove(i);
+            }
+        }
+        for (int i = mMovesList.size() - 1; i >= 0; i--) {
+            ArrayList<MoveInfo> moves = mMovesList.get(i);
+            for (int j = moves.size() - 1; j >= 0; j--) {
+                MoveInfo moveInfo = moves.get(j);
+                if (moveInfo.holder == item) {
+                    view.setTranslationY(0);
+                    view.setTranslationX(0);
+                    dispatchMoveFinished(item);
+                    moves.remove(j);
+                    if (moves.isEmpty()) {
+                        mMovesList.remove(i);
+                    }
+                    break;
+                }
+            }
+        }
+        for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
+            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
+            if (additions.remove(item)) {
+                view.setAlpha(1);
+                dispatchAddFinished(item);
+                if (additions.isEmpty()) {
+                    mAdditionsList.remove(i);
+                }
+            }
+        }
+
+        // animations should be ended by the cancel above.
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mRemoveAnimations.remove(item) && DEBUG) {
+            throw new IllegalStateException("after animation is cancelled, item should not be in "
+                    + "mRemoveAnimations list");
+        }
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mAddAnimations.remove(item) && DEBUG) {
+            throw new IllegalStateException("after animation is cancelled, item should not be in "
+                    + "mAddAnimations list");
+        }
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mChangeAnimations.remove(item) && DEBUG) {
+            throw new IllegalStateException("after animation is cancelled, item should not be in "
+                    + "mChangeAnimations list");
+        }
+
+        //noinspection PointlessBooleanExpression,ConstantConditions
+        if (mMoveAnimations.remove(item) && DEBUG) {
+            throw new IllegalStateException("after animation is cancelled, item should not be in "
+                    + "mMoveAnimations list");
+        }
+        dispatchFinishedWhenDone();
+    }
+
+    private void resetAnimation(ViewHolder holder) {
+        if (sDefaultInterpolator == null) {
+            sDefaultInterpolator = new ValueAnimator().getInterpolator();
+        }
+        holder.itemView.animate().setInterpolator(sDefaultInterpolator);
+        endAnimation(holder);
+    }
+
+    @Override
+    public boolean isRunning() {
+        return (!mPendingAdditions.isEmpty()
+                || !mPendingChanges.isEmpty()
+                || !mPendingMoves.isEmpty()
+                || !mPendingRemovals.isEmpty()
+                || !mMoveAnimations.isEmpty()
+                || !mRemoveAnimations.isEmpty()
+                || !mAddAnimations.isEmpty()
+                || !mChangeAnimations.isEmpty()
+                || !mMovesList.isEmpty()
+                || !mAdditionsList.isEmpty()
+                || !mChangesList.isEmpty());
+    }
+
+    /**
+     * Check the state of currently pending and running animations. If there are none
+     * pending/running, call {@link #dispatchAnimationsFinished()} to notify any
+     * listeners.
+     */
+    void dispatchFinishedWhenDone() {
+        if (!isRunning()) {
+            dispatchAnimationsFinished();
+        }
+    }
+
+    @Override
+    public void endAnimations() {
+        int count = mPendingMoves.size();
+        for (int i = count - 1; i >= 0; i--) {
+            MoveInfo item = mPendingMoves.get(i);
+            View view = item.holder.itemView;
+            view.setTranslationY(0);
+            view.setTranslationX(0);
+            dispatchMoveFinished(item.holder);
+            mPendingMoves.remove(i);
+        }
+        count = mPendingRemovals.size();
+        for (int i = count - 1; i >= 0; i--) {
+            ViewHolder item = mPendingRemovals.get(i);
+            dispatchRemoveFinished(item);
+            mPendingRemovals.remove(i);
+        }
+        count = mPendingAdditions.size();
+        for (int i = count - 1; i >= 0; i--) {
+            ViewHolder item = mPendingAdditions.get(i);
+            item.itemView.setAlpha(1);
+            dispatchAddFinished(item);
+            mPendingAdditions.remove(i);
+        }
+        count = mPendingChanges.size();
+        for (int i = count - 1; i >= 0; i--) {
+            endChangeAnimationIfNecessary(mPendingChanges.get(i));
+        }
+        mPendingChanges.clear();
+        if (!isRunning()) {
+            return;
+        }
+
+        int listCount = mMovesList.size();
+        for (int i = listCount - 1; i >= 0; i--) {
+            ArrayList<MoveInfo> moves = mMovesList.get(i);
+            count = moves.size();
+            for (int j = count - 1; j >= 0; j--) {
+                MoveInfo moveInfo = moves.get(j);
+                ViewHolder item = moveInfo.holder;
+                View view = item.itemView;
+                view.setTranslationY(0);
+                view.setTranslationX(0);
+                dispatchMoveFinished(moveInfo.holder);
+                moves.remove(j);
+                if (moves.isEmpty()) {
+                    mMovesList.remove(moves);
+                }
+            }
+        }
+        listCount = mAdditionsList.size();
+        for (int i = listCount - 1; i >= 0; i--) {
+            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
+            count = additions.size();
+            for (int j = count - 1; j >= 0; j--) {
+                ViewHolder item = additions.get(j);
+                View view = item.itemView;
+                view.setAlpha(1);
+                dispatchAddFinished(item);
+                additions.remove(j);
+                if (additions.isEmpty()) {
+                    mAdditionsList.remove(additions);
+                }
+            }
+        }
+        listCount = mChangesList.size();
+        for (int i = listCount - 1; i >= 0; i--) {
+            ArrayList<ChangeInfo> changes = mChangesList.get(i);
+            count = changes.size();
+            for (int j = count - 1; j >= 0; j--) {
+                endChangeAnimationIfNecessary(changes.get(j));
+                if (changes.isEmpty()) {
+                    mChangesList.remove(changes);
+                }
+            }
+        }
+
+        cancelAll(mRemoveAnimations);
+        cancelAll(mMoveAnimations);
+        cancelAll(mAddAnimations);
+        cancelAll(mChangeAnimations);
+
+        dispatchAnimationsFinished();
+    }
+
+    void cancelAll(List<ViewHolder> viewHolders) {
+        for (int i = viewHolders.size() - 1; i >= 0; i--) {
+            viewHolders.get(i).itemView.animate().cancel();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
+     * When this is the case:
+     * <ul>
+     * <li>If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both
+     * ViewHolder arguments will be the same instance.
+     * </li>
+     * <li>
+     * If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)},
+     * then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and
+     * run a move animation instead.
+     * </li>
+     * </ul>
+     */
+    @Override
+    public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
+            @NonNull List<Object> payloads) {
+        return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
+    }
+}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 04e09a8..58e694a 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -1591,7 +1591,7 @@
                     } else {
                         menuButton.setContentDescription(contentDescription);
                     }
-                    menuButton.setTooltip(menuItem.getTooltip());
+                    menuButton.setTooltipText(menuItem.getTooltipText());
                     menuButton.setMinimumWidth(minimumWidth);
                 }
                 return menuButton;
@@ -1642,17 +1642,17 @@
             ((ImageButton) menuItemButton
                     .findViewById(R.id.floating_toolbar_menu_item_image_button))
                     .setImageDrawable(menuItem.getIcon());
-            final CharSequence tooltip = menuItem.getTooltip();
-            if (TextUtils.isEmpty(tooltip)) {
-                menuItemButton.setTooltip(menuItem.getTitle());
+            final CharSequence tooltipText = menuItem.getTooltipText();
+            if (TextUtils.isEmpty(tooltipText)) {
+                menuItemButton.setTooltipText(menuItem.getTitle());
             } else {
-                menuItemButton.setTooltip(tooltip);
+                menuItemButton.setTooltipText(tooltipText);
             }
         } else {
             menuItemButton = LayoutInflater.from(context)
                     .inflate(R.layout.floating_popup_menu_button, null);
             ((Button) menuItemButton).setText(menuItem.getTitle());
-            menuItemButton.setTooltip(menuItem.getTooltip());
+            menuItemButton.setTooltipText(menuItem.getTooltipText());
         }
         final CharSequence contentDescription = menuItem.getContentDescription();
         if (TextUtils.isEmpty(contentDescription)) {
diff --git a/core/java/com/android/internal/widget/GapWorker.java b/core/java/com/android/internal/widget/GapWorker.java
new file mode 100644
index 0000000..5972396
--- /dev/null
+++ b/core/java/com/android/internal/widget/GapWorker.java
@@ -0,0 +1,379 @@
+/*
+ * 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.widget;
+
+import android.annotation.Nullable;
+import android.os.Trace;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.concurrent.TimeUnit;
+
+final class GapWorker implements Runnable {
+
+    static final ThreadLocal<GapWorker> sGapWorker = new ThreadLocal<>();
+
+    ArrayList<RecyclerView> mRecyclerViews = new ArrayList<>();
+    long mPostTimeNs;
+    long mFrameIntervalNs;
+
+    static class Task {
+        public boolean immediate;
+        public int viewVelocity;
+        public int distanceToItem;
+        public RecyclerView view;
+        public int position;
+
+        public void clear() {
+            immediate = false;
+            viewVelocity = 0;
+            distanceToItem = 0;
+            view = null;
+            position = 0;
+        }
+    }
+
+    /**
+     * Temporary storage for prefetch Tasks that execute in {@link #prefetch(long)}. Task objects
+     * are pooled in the ArrayList, and never removed to avoid allocations, but always cleared
+     * in between calls.
+     */
+    private ArrayList<Task> mTasks = new ArrayList<>();
+
+    /**
+     * Prefetch information associated with a specific RecyclerView.
+     */
+    static class LayoutPrefetchRegistryImpl
+            implements RecyclerView.LayoutManager.LayoutPrefetchRegistry {
+        int mPrefetchDx;
+        int mPrefetchDy;
+        int[] mPrefetchArray;
+
+        int mCount;
+
+        void setPrefetchVector(int dx, int dy) {
+            mPrefetchDx = dx;
+            mPrefetchDy = dy;
+        }
+
+        void collectPrefetchPositionsFromView(RecyclerView view, boolean nested) {
+            mCount = 0;
+            if (mPrefetchArray != null) {
+                Arrays.fill(mPrefetchArray, -1);
+            }
+
+            final RecyclerView.LayoutManager layout = view.mLayout;
+            if (view.mAdapter != null
+                    && layout != null
+                    && layout.isItemPrefetchEnabled()) {
+                if (nested) {
+                    // nested prefetch, only if no adapter updates pending. Note: we don't query
+                    // view.hasPendingAdapterUpdates(), as first layout may not have occurred
+                    if (!view.mAdapterHelper.hasPendingUpdates()) {
+                        layout.collectInitialPrefetchPositions(view.mAdapter.getItemCount(), this);
+                    }
+                } else {
+                    // momentum based prefetch, only if we trust current child/adapter state
+                    if (!view.hasPendingAdapterUpdates()) {
+                        layout.collectAdjacentPrefetchPositions(mPrefetchDx, mPrefetchDy,
+                                view.mState, this);
+                    }
+                }
+
+                if (mCount > layout.mPrefetchMaxCountObserved) {
+                    layout.mPrefetchMaxCountObserved = mCount;
+                    layout.mPrefetchMaxObservedInInitialPrefetch = nested;
+                    view.mRecycler.updateViewCacheSize();
+                }
+            }
+        }
+
+        @Override
+        public void addPosition(int layoutPosition, int pixelDistance) {
+            if (pixelDistance < 0) {
+                throw new IllegalArgumentException("Pixel distance must be non-negative");
+            }
+
+            // allocate or expand array as needed, doubling when needed
+            final int storagePosition = mCount * 2;
+            if (mPrefetchArray == null) {
+                mPrefetchArray = new int[4];
+                Arrays.fill(mPrefetchArray, -1);
+            } else if (storagePosition >= mPrefetchArray.length) {
+                final int[] oldArray = mPrefetchArray;
+                mPrefetchArray = new int[storagePosition * 2];
+                System.arraycopy(oldArray, 0, mPrefetchArray, 0, oldArray.length);
+            }
+
+            // add position
+            mPrefetchArray[storagePosition] = layoutPosition;
+            mPrefetchArray[storagePosition + 1] = pixelDistance;
+
+            mCount++;
+        }
+
+        boolean lastPrefetchIncludedPosition(int position) {
+            if (mPrefetchArray != null) {
+                final int count = mCount * 2;
+                for (int i = 0; i < count; i += 2) {
+                    if (mPrefetchArray[i] == position) return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Called when prefetch indices are no longer valid for cache prioritization.
+         */
+        void clearPrefetchPositions() {
+            if (mPrefetchArray != null) {
+                Arrays.fill(mPrefetchArray, -1);
+            }
+        }
+    }
+
+    public void add(RecyclerView recyclerView) {
+        if (RecyclerView.DEBUG && mRecyclerViews.contains(recyclerView)) {
+            throw new IllegalStateException("RecyclerView already present in worker list!");
+        }
+        mRecyclerViews.add(recyclerView);
+    }
+
+    public void remove(RecyclerView recyclerView) {
+        boolean removeSuccess = mRecyclerViews.remove(recyclerView);
+        if (RecyclerView.DEBUG && !removeSuccess) {
+            throw new IllegalStateException("RecyclerView removal failed!");
+        }
+    }
+
+    /**
+     * Schedule a prefetch immediately after the current traversal.
+     */
+    void postFromTraversal(RecyclerView recyclerView, int prefetchDx, int prefetchDy) {
+        if (recyclerView.isAttachedToWindow()) {
+            if (RecyclerView.DEBUG && !mRecyclerViews.contains(recyclerView)) {
+                throw new IllegalStateException("attempting to post unregistered view!");
+            }
+            if (mPostTimeNs == 0) {
+                mPostTimeNs = recyclerView.getNanoTime();
+                recyclerView.post(this);
+            }
+        }
+
+        recyclerView.mPrefetchRegistry.setPrefetchVector(prefetchDx, prefetchDy);
+    }
+
+    static Comparator<Task> sTaskComparator = new Comparator<Task>() {
+        @Override
+        public int compare(Task lhs, Task rhs) {
+            // first, prioritize non-cleared tasks
+            if ((lhs.view == null) != (rhs.view == null)) {
+                return lhs.view == null ? 1 : -1;
+            }
+
+            // then prioritize immediate
+            if (lhs.immediate != rhs.immediate) {
+                return lhs.immediate ? -1 : 1;
+            }
+
+            // then prioritize _highest_ view velocity
+            int deltaViewVelocity = rhs.viewVelocity - lhs.viewVelocity;
+            if (deltaViewVelocity != 0) return deltaViewVelocity;
+
+            // then prioritize _lowest_ distance to item
+            int deltaDistanceToItem = lhs.distanceToItem - rhs.distanceToItem;
+            if (deltaDistanceToItem != 0) return deltaDistanceToItem;
+
+            return 0;
+        }
+    };
+
+    private void buildTaskList() {
+        // Update PrefetchRegistry in each view
+        final int viewCount = mRecyclerViews.size();
+        int totalTaskCount = 0;
+        for (int i = 0; i < viewCount; i++) {
+            RecyclerView view = mRecyclerViews.get(i);
+            view.mPrefetchRegistry.collectPrefetchPositionsFromView(view, false);
+            totalTaskCount += view.mPrefetchRegistry.mCount;
+        }
+
+        // Populate task list from prefetch data...
+        mTasks.ensureCapacity(totalTaskCount);
+        int totalTaskIndex = 0;
+        for (int i = 0; i < viewCount; i++) {
+            RecyclerView view = mRecyclerViews.get(i);
+            LayoutPrefetchRegistryImpl prefetchRegistry = view.mPrefetchRegistry;
+            final int viewVelocity = Math.abs(prefetchRegistry.mPrefetchDx)
+                    + Math.abs(prefetchRegistry.mPrefetchDy);
+            for (int j = 0; j < prefetchRegistry.mCount * 2; j += 2) {
+                final Task task;
+                if (totalTaskIndex >= mTasks.size()) {
+                    task = new Task();
+                    mTasks.add(task);
+                } else {
+                    task = mTasks.get(totalTaskIndex);
+                }
+                final int distanceToItem = prefetchRegistry.mPrefetchArray[j + 1];
+
+                task.immediate = distanceToItem <= viewVelocity;
+                task.viewVelocity = viewVelocity;
+                task.distanceToItem = distanceToItem;
+                task.view = view;
+                task.position = prefetchRegistry.mPrefetchArray[j];
+
+                totalTaskIndex++;
+            }
+        }
+
+        // ... and priority sort
+        Collections.sort(mTasks, sTaskComparator);
+    }
+
+    static boolean isPrefetchPositionAttached(RecyclerView view, int position) {
+        final int childCount = view.mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View attachedView = view.mChildHelper.getUnfilteredChildAt(i);
+            RecyclerView.ViewHolder holder = RecyclerView.getChildViewHolderInt(attachedView);
+            // Note: can use mPosition here because adapter doesn't have pending updates
+            if (holder.mPosition == position && !holder.isInvalid()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private RecyclerView.ViewHolder prefetchPositionWithDeadline(RecyclerView view,
+            int position, long deadlineNs) {
+        if (isPrefetchPositionAttached(view, position)) {
+            // don't attempt to prefetch attached views
+            return null;
+        }
+
+        RecyclerView.Recycler recycler = view.mRecycler;
+        RecyclerView.ViewHolder holder = recycler.tryGetViewHolderForPositionByDeadline(
+                position, false, deadlineNs);
+
+        if (holder != null) {
+            if (holder.isBound()) {
+                // Only give the view a chance to go into the cache if binding succeeded
+                // Note that we must use public method, since item may need cleanup
+                recycler.recycleView(holder.itemView);
+            } else {
+                // Didn't bind, so we can't cache the view, but it will stay in the pool until
+                // next prefetch/traversal. If a View fails to bind, it means we didn't have
+                // enough time prior to the deadline (and won't for other instances of this
+                // type, during this GapWorker prefetch pass).
+                recycler.addViewHolderToRecycledViewPool(holder, false);
+            }
+        }
+        return holder;
+    }
+
+    private void prefetchInnerRecyclerViewWithDeadline(@Nullable RecyclerView innerView,
+            long deadlineNs) {
+        if (innerView == null) {
+            return;
+        }
+
+        if (innerView.mDataSetHasChangedAfterLayout
+                && innerView.mChildHelper.getUnfilteredChildCount() != 0) {
+            // RecyclerView has new data, but old attached views. Clear everything, so that
+            // we can prefetch without partially stale data.
+            innerView.removeAndRecycleViews();
+        }
+
+        // do nested prefetch!
+        final LayoutPrefetchRegistryImpl innerPrefetchRegistry = innerView.mPrefetchRegistry;
+        innerPrefetchRegistry.collectPrefetchPositionsFromView(innerView, true);
+
+        if (innerPrefetchRegistry.mCount != 0) {
+            try {
+                Trace.beginSection(RecyclerView.TRACE_NESTED_PREFETCH_TAG);
+                innerView.mState.prepareForNestedPrefetch(innerView.mAdapter);
+                for (int i = 0; i < innerPrefetchRegistry.mCount * 2; i += 2) {
+                    // Note that we ignore immediate flag for inner items because
+                    // we have lower confidence they're needed next frame.
+                    final int innerPosition = innerPrefetchRegistry.mPrefetchArray[i];
+                    prefetchPositionWithDeadline(innerView, innerPosition, deadlineNs);
+                }
+            } finally {
+                Trace.endSection();
+            }
+        }
+    }
+
+    private void flushTaskWithDeadline(Task task, long deadlineNs) {
+        long taskDeadlineNs = task.immediate ? RecyclerView.FOREVER_NS : deadlineNs;
+        RecyclerView.ViewHolder holder = prefetchPositionWithDeadline(task.view,
+                task.position, taskDeadlineNs);
+        if (holder != null && holder.mNestedRecyclerView != null) {
+            prefetchInnerRecyclerViewWithDeadline(holder.mNestedRecyclerView.get(), deadlineNs);
+        }
+    }
+
+    private void flushTasksWithDeadline(long deadlineNs) {
+        for (int i = 0; i < mTasks.size(); i++) {
+            final Task task = mTasks.get(i);
+            if (task.view == null) {
+                break; // done with populated tasks
+            }
+            flushTaskWithDeadline(task, deadlineNs);
+            task.clear();
+        }
+    }
+
+    void prefetch(long deadlineNs) {
+        buildTaskList();
+        flushTasksWithDeadline(deadlineNs);
+    }
+
+    @Override
+    public void run() {
+        try {
+            Trace.beginSection(RecyclerView.TRACE_PREFETCH_TAG);
+
+            if (mRecyclerViews.isEmpty()) {
+                // abort - no work to do
+                return;
+            }
+
+            // Query last vsync so we can predict next one. Note that drawing time not yet
+            // valid in animation/input callbacks, so query it here to be safe.
+            long lastFrameVsyncNs = TimeUnit.MILLISECONDS.toNanos(
+                    mRecyclerViews.get(0).getDrawingTime());
+            if (lastFrameVsyncNs == 0) {
+                // abort - couldn't get last vsync for estimating next
+                return;
+            }
+
+            // TODO: consider rebasing deadline if frame was already dropped due to long UI work.
+            // Next frame will still wait for VSYNC, so we can still use the gap if it exists.
+            long nextFrameNs = lastFrameVsyncNs + mFrameIntervalNs;
+
+            prefetch(nextFrameNs);
+
+            // TODO: consider rescheduling self, if there's more work to do
+        } finally {
+            mPostTimeNs = 0;
+            Trace.endSection();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/LinearLayoutManager.java b/core/java/com/android/internal/widget/LinearLayoutManager.java
new file mode 100644
index 0000000..d82c746
--- /dev/null
+++ b/core/java/com/android/internal/widget/LinearLayoutManager.java
@@ -0,0 +1,2398 @@
+/*
+ * 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.widget;
+
+import static com.android.internal.widget.RecyclerView.NO_POSITION;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.internal.widget.RecyclerView.LayoutParams;
+import com.android.internal.widget.helper.ItemTouchHelper;
+
+import java.util.List;
+
+/**
+ * A {@link com.android.internal.widget.RecyclerView.LayoutManager} implementation which provides
+ * similar functionality to {@link android.widget.ListView}.
+ */
+public class LinearLayoutManager extends RecyclerView.LayoutManager implements
+        ItemTouchHelper.ViewDropHandler, RecyclerView.SmoothScroller.ScrollVectorProvider {
+
+    private static final String TAG = "LinearLayoutManager";
+
+    static final boolean DEBUG = false;
+
+    public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
+
+    public static final int VERTICAL = OrientationHelper.VERTICAL;
+
+    public static final int INVALID_OFFSET = Integer.MIN_VALUE;
+
+
+    /**
+     * While trying to find next view to focus, LayoutManager will not try to scroll more
+     * than this factor times the total space of the list. If layout is vertical, total space is the
+     * height minus padding, if layout is horizontal, total space is the width minus padding.
+     */
+    private static final float MAX_SCROLL_FACTOR = 1 / 3f;
+
+
+    /**
+     * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}
+     */
+    int mOrientation;
+
+    /**
+     * Helper class that keeps temporary layout state.
+     * It does not keep state after layout is complete but we still keep a reference to re-use
+     * the same object.
+     */
+    private LayoutState mLayoutState;
+
+    /**
+     * Many calculations are made depending on orientation. To keep it clean, this interface
+     * helps {@link LinearLayoutManager} make those decisions.
+     * Based on {@link #mOrientation}, an implementation is lazily created in
+     * {@link #ensureLayoutState} method.
+     */
+    OrientationHelper mOrientationHelper;
+
+    /**
+     * We need to track this so that we can ignore current position when it changes.
+     */
+    private boolean mLastStackFromEnd;
+
+
+    /**
+     * Defines if layout should be calculated from end to start.
+     *
+     * @see #mShouldReverseLayout
+     */
+    private boolean mReverseLayout = false;
+
+    /**
+     * This keeps the final value for how LayoutManager should start laying out views.
+     * It is calculated by checking {@link #getReverseLayout()} and View's layout direction.
+     * {@link #onLayoutChildren(RecyclerView.Recycler, RecyclerView.State)} is run.
+     */
+    boolean mShouldReverseLayout = false;
+
+    /**
+     * Works the same way as {@link android.widget.AbsListView#setStackFromBottom(boolean)} and
+     * it supports both orientations.
+     * see {@link android.widget.AbsListView#setStackFromBottom(boolean)}
+     */
+    private boolean mStackFromEnd = false;
+
+    /**
+     * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}.
+     * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}
+     */
+    private boolean mSmoothScrollbarEnabled = true;
+
+    /**
+     * When LayoutManager needs to scroll to a position, it sets this variable and requests a
+     * layout which will check this variable and re-layout accordingly.
+     */
+    int mPendingScrollPosition = NO_POSITION;
+
+    /**
+     * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
+     * called.
+     */
+    int mPendingScrollPositionOffset = INVALID_OFFSET;
+
+    private boolean mRecycleChildrenOnDetach;
+
+    SavedState mPendingSavedState = null;
+
+    /**
+     *  Re-used variable to keep anchor information on re-layout.
+     *  Anchor position and coordinate defines the reference point for LLM while doing a layout.
+     * */
+    final AnchorInfo mAnchorInfo = new AnchorInfo();
+
+    /**
+     * Stashed to avoid allocation, currently only used in #fill()
+     */
+    private final LayoutChunkResult mLayoutChunkResult = new LayoutChunkResult();
+
+    /**
+     * Number of items to prefetch when first coming on screen with new data.
+     */
+    private int mInitialItemPrefetchCount = 2;
+
+    /**
+     * Creates a vertical LinearLayoutManager
+     *
+     * @param context Current context, will be used to access resources.
+     */
+    public LinearLayoutManager(Context context) {
+        this(context, VERTICAL, false);
+    }
+
+    /**
+     * @param context       Current context, will be used to access resources.
+     * @param orientation   Layout orientation. Should be {@link #HORIZONTAL} or {@link
+     *                      #VERTICAL}.
+     * @param reverseLayout When set to true, layouts from end to start.
+     */
+    public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
+        setOrientation(orientation);
+        setReverseLayout(reverseLayout);
+        setAutoMeasureEnabled(true);
+    }
+
+    /**
+     * Constructor used when layout manager is set in XML by RecyclerView attribute
+     * "layoutManager". Defaults to vertical orientation.
+     *
+     * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation
+     * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout
+     * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd
+     */
+    public LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
+        setOrientation(properties.orientation);
+        setReverseLayout(properties.reverseLayout);
+        setStackFromEnd(properties.stackFromEnd);
+        setAutoMeasureEnabled(true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+    }
+
+    /**
+     * Returns whether LayoutManager will recycle its children when it is detached from
+     * RecyclerView.
+     *
+     * @return true if LayoutManager will recycle its children when it is detached from
+     * RecyclerView.
+     */
+    public boolean getRecycleChildrenOnDetach() {
+        return mRecycleChildrenOnDetach;
+    }
+
+    /**
+     * Set whether LayoutManager will recycle its children when it is detached from
+     * RecyclerView.
+     * <p>
+     * If you are using a {@link RecyclerView.RecycledViewPool}, it might be a good idea to set
+     * this flag to <code>true</code> so that views will be available to other RecyclerViews
+     * immediately.
+     * <p>
+     * Note that, setting this flag will result in a performance drop if RecyclerView
+     * is restored.
+     *
+     * @param recycleChildrenOnDetach Whether children should be recycled in detach or not.
+     */
+    public void setRecycleChildrenOnDetach(boolean recycleChildrenOnDetach) {
+        mRecycleChildrenOnDetach = recycleChildrenOnDetach;
+    }
+
+    @Override
+    public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+        super.onDetachedFromWindow(view, recycler);
+        if (mRecycleChildrenOnDetach) {
+            removeAndRecycleAllViews(recycler);
+            recycler.clear();
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        if (getChildCount() > 0) {
+            event.setFromIndex(findFirstVisibleItemPosition());
+            event.setToIndex(findLastVisibleItemPosition());
+        }
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        if (mPendingSavedState != null) {
+            return new SavedState(mPendingSavedState);
+        }
+        SavedState state = new SavedState();
+        if (getChildCount() > 0) {
+            ensureLayoutState();
+            boolean didLayoutFromEnd = mLastStackFromEnd ^ mShouldReverseLayout;
+            state.mAnchorLayoutFromEnd = didLayoutFromEnd;
+            if (didLayoutFromEnd) {
+                final View refChild = getChildClosestToEnd();
+                state.mAnchorOffset = mOrientationHelper.getEndAfterPadding()
+                        - mOrientationHelper.getDecoratedEnd(refChild);
+                state.mAnchorPosition = getPosition(refChild);
+            } else {
+                final View refChild = getChildClosestToStart();
+                state.mAnchorPosition = getPosition(refChild);
+                state.mAnchorOffset = mOrientationHelper.getDecoratedStart(refChild)
+                        - mOrientationHelper.getStartAfterPadding();
+            }
+        } else {
+            state.invalidateAnchor();
+        }
+        return state;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (state instanceof SavedState) {
+            mPendingSavedState = (SavedState) state;
+            requestLayout();
+            if (DEBUG) {
+                Log.d(TAG, "loaded saved state");
+            }
+        } else if (DEBUG) {
+            Log.d(TAG, "invalid saved state class");
+        }
+    }
+
+    /**
+     * @return true if {@link #getOrientation()} is {@link #HORIZONTAL}
+     */
+    @Override
+    public boolean canScrollHorizontally() {
+        return mOrientation == HORIZONTAL;
+    }
+
+    /**
+     * @return true if {@link #getOrientation()} is {@link #VERTICAL}
+     */
+    @Override
+    public boolean canScrollVertically() {
+        return mOrientation == VERTICAL;
+    }
+
+    /**
+     * Compatibility support for {@link android.widget.AbsListView#setStackFromBottom(boolean)}
+     */
+    public void setStackFromEnd(boolean stackFromEnd) {
+        assertNotInLayoutOrScroll(null);
+        if (mStackFromEnd == stackFromEnd) {
+            return;
+        }
+        mStackFromEnd = stackFromEnd;
+        requestLayout();
+    }
+
+    public boolean getStackFromEnd() {
+        return mStackFromEnd;
+    }
+
+    /**
+     * Returns the current orientation of the layout.
+     *
+     * @return Current orientation,  either {@link #HORIZONTAL} or {@link #VERTICAL}
+     * @see #setOrientation(int)
+     */
+    public int getOrientation() {
+        return mOrientation;
+    }
+
+    /**
+     * Sets the orientation of the layout. {@link com.android.internal.widget.LinearLayoutManager}
+     * will do its best to keep scroll position.
+     *
+     * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
+     */
+    public void setOrientation(int orientation) {
+        if (orientation != HORIZONTAL && orientation != VERTICAL) {
+            throw new IllegalArgumentException("invalid orientation:" + orientation);
+        }
+        assertNotInLayoutOrScroll(null);
+        if (orientation == mOrientation) {
+            return;
+        }
+        mOrientation = orientation;
+        mOrientationHelper = null;
+        requestLayout();
+    }
+
+    /**
+     * Calculates the view layout order. (e.g. from end to start or start to end)
+     * RTL layout support is applied automatically. So if layout is RTL and
+     * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left.
+     */
+    private void resolveShouldLayoutReverse() {
+        // A == B is the same result, but we rather keep it readable
+        if (mOrientation == VERTICAL || !isLayoutRTL()) {
+            mShouldReverseLayout = mReverseLayout;
+        } else {
+            mShouldReverseLayout = !mReverseLayout;
+        }
+    }
+
+    /**
+     * Returns if views are laid out from the opposite direction of the layout.
+     *
+     * @return If layout is reversed or not.
+     * @see #setReverseLayout(boolean)
+     */
+    public boolean getReverseLayout() {
+        return mReverseLayout;
+    }
+
+    /**
+     * Used to reverse item traversal and layout order.
+     * This behaves similar to the layout change for RTL views. When set to true, first item is
+     * laid out at the end of the UI, second item is laid out before it etc.
+     *
+     * For horizontal layouts, it depends on the layout direction.
+     * When set to true, If {@link com.android.internal.widget.RecyclerView} is LTR, than it will
+     * layout from RTL, if {@link com.android.internal.widget.RecyclerView}} is RTL, it will layout
+     * from LTR.
+     *
+     * If you are looking for the exact same behavior of
+     * {@link android.widget.AbsListView#setStackFromBottom(boolean)}, use
+     * {@link #setStackFromEnd(boolean)}
+     */
+    public void setReverseLayout(boolean reverseLayout) {
+        assertNotInLayoutOrScroll(null);
+        if (reverseLayout == mReverseLayout) {
+            return;
+        }
+        mReverseLayout = reverseLayout;
+        requestLayout();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View findViewByPosition(int position) {
+        final int childCount = getChildCount();
+        if (childCount == 0) {
+            return null;
+        }
+        final int firstChild = getPosition(getChildAt(0));
+        final int viewPosition = position - firstChild;
+        if (viewPosition >= 0 && viewPosition < childCount) {
+            final View child = getChildAt(viewPosition);
+            if (getPosition(child) == position) {
+                return child; // in pre-layout, this may not match
+            }
+        }
+        // fallback to traversal. This might be necessary in pre-layout.
+        return super.findViewByPosition(position);
+    }
+
+    /**
+     * <p>Returns the amount of extra space that should be laid out by LayoutManager.</p>
+     *
+     * <p>By default, {@link com.android.internal.widget.LinearLayoutManager} lays out 1 extra page
+     * of items while smooth scrolling and 0 otherwise. You can override this method to implement
+     * your custom layout pre-cache logic.</p>
+     *
+     * <p><strong>Note:</strong>Laying out invisible elements generally comes with significant
+     * performance cost. It's typically only desirable in places like smooth scrolling to an unknown
+     * location, where 1) the extra content helps LinearLayoutManager know in advance when its
+     * target is approaching, so it can decelerate early and smoothly and 2) while motion is
+     * continuous.</p>
+     *
+     * <p>Extending the extra layout space is especially expensive if done while the user may change
+     * scrolling direction. Changing direction will cause the extra layout space to swap to the
+     * opposite side of the viewport, incurring many rebinds/recycles, unless the cache is large
+     * enough to handle it.</p>
+     *
+     * @return The extra space that should be laid out (in pixels).
+     */
+    protected int getExtraLayoutSpace(RecyclerView.State state) {
+        if (state.hasTargetScrollPosition()) {
+            return mOrientationHelper.getTotalSpace();
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
+            int position) {
+        LinearSmoothScroller linearSmoothScroller =
+                new LinearSmoothScroller(recyclerView.getContext());
+        linearSmoothScroller.setTargetPosition(position);
+        startSmoothScroll(linearSmoothScroller);
+    }
+
+    @Override
+    public PointF computeScrollVectorForPosition(int targetPosition) {
+        if (getChildCount() == 0) {
+            return null;
+        }
+        final int firstChildPos = getPosition(getChildAt(0));
+        final int direction = targetPosition < firstChildPos != mShouldReverseLayout ? -1 : 1;
+        if (mOrientation == HORIZONTAL) {
+            return new PointF(direction, 0);
+        } else {
+            return new PointF(0, direction);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        // layout algorithm:
+        // 1) by checking children and other variables, find an anchor coordinate and an anchor
+        //  item position.
+        // 2) fill towards start, stacking from bottom
+        // 3) fill towards end, stacking from top
+        // 4) scroll to fulfill requirements like stack from bottom.
+        // create layout state
+        if (DEBUG) {
+            Log.d(TAG, "is pre layout:" + state.isPreLayout());
+        }
+        if (mPendingSavedState != null || mPendingScrollPosition != NO_POSITION) {
+            if (state.getItemCount() == 0) {
+                removeAndRecycleAllViews(recycler);
+                return;
+            }
+        }
+        if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) {
+            mPendingScrollPosition = mPendingSavedState.mAnchorPosition;
+        }
+
+        ensureLayoutState();
+        mLayoutState.mRecycle = false;
+        // resolve layout direction
+        resolveShouldLayoutReverse();
+
+        if (!mAnchorInfo.mValid || mPendingScrollPosition != NO_POSITION
+                || mPendingSavedState != null) {
+            mAnchorInfo.reset();
+            mAnchorInfo.mLayoutFromEnd = mShouldReverseLayout ^ mStackFromEnd;
+            // calculate anchor position and coordinate
+            updateAnchorInfoForLayout(recycler, state, mAnchorInfo);
+            mAnchorInfo.mValid = true;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Anchor info:" + mAnchorInfo);
+        }
+
+        // LLM may decide to layout items for "extra" pixels to account for scrolling target,
+        // caching or predictive animations.
+        int extraForStart;
+        int extraForEnd;
+        final int extra = getExtraLayoutSpace(state);
+        // If the previous scroll delta was less than zero, the extra space should be laid out
+        // at the start. Otherwise, it should be at the end.
+        if (mLayoutState.mLastScrollDelta >= 0) {
+            extraForEnd = extra;
+            extraForStart = 0;
+        } else {
+            extraForStart = extra;
+            extraForEnd = 0;
+        }
+        extraForStart += mOrientationHelper.getStartAfterPadding();
+        extraForEnd += mOrientationHelper.getEndPadding();
+        if (state.isPreLayout() && mPendingScrollPosition != NO_POSITION
+                && mPendingScrollPositionOffset != INVALID_OFFSET) {
+            // if the child is visible and we are going to move it around, we should layout
+            // extra items in the opposite direction to make sure new items animate nicely
+            // instead of just fading in
+            final View existing = findViewByPosition(mPendingScrollPosition);
+            if (existing != null) {
+                final int current;
+                final int upcomingOffset;
+                if (mShouldReverseLayout) {
+                    current = mOrientationHelper.getEndAfterPadding()
+                            - mOrientationHelper.getDecoratedEnd(existing);
+                    upcomingOffset = current - mPendingScrollPositionOffset;
+                } else {
+                    current = mOrientationHelper.getDecoratedStart(existing)
+                            - mOrientationHelper.getStartAfterPadding();
+                    upcomingOffset = mPendingScrollPositionOffset - current;
+                }
+                if (upcomingOffset > 0) {
+                    extraForStart += upcomingOffset;
+                } else {
+                    extraForEnd -= upcomingOffset;
+                }
+            }
+        }
+        int startOffset;
+        int endOffset;
+        final int firstLayoutDirection;
+        if (mAnchorInfo.mLayoutFromEnd) {
+            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
+                    : LayoutState.ITEM_DIRECTION_HEAD;
+        } else {
+            firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
+                    : LayoutState.ITEM_DIRECTION_TAIL;
+        }
+
+        onAnchorReady(recycler, state, mAnchorInfo, firstLayoutDirection);
+        detachAndScrapAttachedViews(recycler);
+        mLayoutState.mInfinite = resolveIsInfinite();
+        mLayoutState.mIsPreLayout = state.isPreLayout();
+        if (mAnchorInfo.mLayoutFromEnd) {
+            // fill towards start
+            updateLayoutStateToFillStart(mAnchorInfo);
+            mLayoutState.mExtra = extraForStart;
+            fill(recycler, mLayoutState, state, false);
+            startOffset = mLayoutState.mOffset;
+            final int firstElement = mLayoutState.mCurrentPosition;
+            if (mLayoutState.mAvailable > 0) {
+                extraForEnd += mLayoutState.mAvailable;
+            }
+            // fill towards end
+            updateLayoutStateToFillEnd(mAnchorInfo);
+            mLayoutState.mExtra = extraForEnd;
+            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
+            fill(recycler, mLayoutState, state, false);
+            endOffset = mLayoutState.mOffset;
+
+            if (mLayoutState.mAvailable > 0) {
+                // end could not consume all. add more items towards start
+                extraForStart = mLayoutState.mAvailable;
+                updateLayoutStateToFillStart(firstElement, startOffset);
+                mLayoutState.mExtra = extraForStart;
+                fill(recycler, mLayoutState, state, false);
+                startOffset = mLayoutState.mOffset;
+            }
+        } else {
+            // fill towards end
+            updateLayoutStateToFillEnd(mAnchorInfo);
+            mLayoutState.mExtra = extraForEnd;
+            fill(recycler, mLayoutState, state, false);
+            endOffset = mLayoutState.mOffset;
+            final int lastElement = mLayoutState.mCurrentPosition;
+            if (mLayoutState.mAvailable > 0) {
+                extraForStart += mLayoutState.mAvailable;
+            }
+            // fill towards start
+            updateLayoutStateToFillStart(mAnchorInfo);
+            mLayoutState.mExtra = extraForStart;
+            mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
+            fill(recycler, mLayoutState, state, false);
+            startOffset = mLayoutState.mOffset;
+
+            if (mLayoutState.mAvailable > 0) {
+                extraForEnd = mLayoutState.mAvailable;
+                // start could not consume all it should. add more items towards end
+                updateLayoutStateToFillEnd(lastElement, endOffset);
+                mLayoutState.mExtra = extraForEnd;
+                fill(recycler, mLayoutState, state, false);
+                endOffset = mLayoutState.mOffset;
+            }
+        }
+
+        // changes may cause gaps on the UI, try to fix them.
+        // TODO we can probably avoid this if neither stackFromEnd/reverseLayout/RTL values have
+        // changed
+        if (getChildCount() > 0) {
+            // because layout from end may be changed by scroll to position
+            // we re-calculate it.
+            // find which side we should check for gaps.
+            if (mShouldReverseLayout ^ mStackFromEnd) {
+                int fixOffset = fixLayoutEndGap(endOffset, recycler, state, true);
+                startOffset += fixOffset;
+                endOffset += fixOffset;
+                fixOffset = fixLayoutStartGap(startOffset, recycler, state, false);
+                startOffset += fixOffset;
+                endOffset += fixOffset;
+            } else {
+                int fixOffset = fixLayoutStartGap(startOffset, recycler, state, true);
+                startOffset += fixOffset;
+                endOffset += fixOffset;
+                fixOffset = fixLayoutEndGap(endOffset, recycler, state, false);
+                startOffset += fixOffset;
+                endOffset += fixOffset;
+            }
+        }
+        layoutForPredictiveAnimations(recycler, state, startOffset, endOffset);
+        if (!state.isPreLayout()) {
+            mOrientationHelper.onLayoutComplete();
+        } else {
+            mAnchorInfo.reset();
+        }
+        mLastStackFromEnd = mStackFromEnd;
+        if (DEBUG) {
+            validateChildOrder();
+        }
+    }
+
+    @Override
+    public void onLayoutCompleted(RecyclerView.State state) {
+        super.onLayoutCompleted(state);
+        mPendingSavedState = null; // we don't need this anymore
+        mPendingScrollPosition = NO_POSITION;
+        mPendingScrollPositionOffset = INVALID_OFFSET;
+        mAnchorInfo.reset();
+    }
+
+    /**
+     * Method called when Anchor position is decided. Extending class can setup accordingly or
+     * even update anchor info if necessary.
+     * @param recycler The recycler for the layout
+     * @param state The layout state
+     * @param anchorInfo The mutable POJO that keeps the position and offset.
+     * @param firstLayoutItemDirection The direction of the first layout filling in terms of adapter
+     *                                 indices.
+     */
+    void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
+            AnchorInfo anchorInfo, int firstLayoutItemDirection) {
+    }
+
+    /**
+     * If necessary, layouts new items for predictive animations
+     */
+    private void layoutForPredictiveAnimations(RecyclerView.Recycler recycler,
+            RecyclerView.State state, int startOffset,  int endOffset) {
+        // If there are scrap children that we did not layout, we need to find where they did go
+        // and layout them accordingly so that animations can work as expected.
+        // This case may happen if new views are added or an existing view expands and pushes
+        // another view out of bounds.
+        if (!state.willRunPredictiveAnimations() ||  getChildCount() == 0 || state.isPreLayout()
+                || !supportsPredictiveItemAnimations()) {
+            return;
+        }
+        // to make the logic simpler, we calculate the size of children and call fill.
+        int scrapExtraStart = 0, scrapExtraEnd = 0;
+        final List<RecyclerView.ViewHolder> scrapList = recycler.getScrapList();
+        final int scrapSize = scrapList.size();
+        final int firstChildPos = getPosition(getChildAt(0));
+        for (int i = 0; i < scrapSize; i++) {
+            RecyclerView.ViewHolder scrap = scrapList.get(i);
+            if (scrap.isRemoved()) {
+                continue;
+            }
+            final int position = scrap.getLayoutPosition();
+            final int direction = position < firstChildPos != mShouldReverseLayout
+                    ? LayoutState.LAYOUT_START : LayoutState.LAYOUT_END;
+            if (direction == LayoutState.LAYOUT_START) {
+                scrapExtraStart += mOrientationHelper.getDecoratedMeasurement(scrap.itemView);
+            } else {
+                scrapExtraEnd += mOrientationHelper.getDecoratedMeasurement(scrap.itemView);
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "for unused scrap, decided to add " + scrapExtraStart
+                    + " towards start and " + scrapExtraEnd + " towards end");
+        }
+        mLayoutState.mScrapList = scrapList;
+        if (scrapExtraStart > 0) {
+            View anchor = getChildClosestToStart();
+            updateLayoutStateToFillStart(getPosition(anchor), startOffset);
+            mLayoutState.mExtra = scrapExtraStart;
+            mLayoutState.mAvailable = 0;
+            mLayoutState.assignPositionFromScrapList();
+            fill(recycler, mLayoutState, state, false);
+        }
+
+        if (scrapExtraEnd > 0) {
+            View anchor = getChildClosestToEnd();
+            updateLayoutStateToFillEnd(getPosition(anchor), endOffset);
+            mLayoutState.mExtra = scrapExtraEnd;
+            mLayoutState.mAvailable = 0;
+            mLayoutState.assignPositionFromScrapList();
+            fill(recycler, mLayoutState, state, false);
+        }
+        mLayoutState.mScrapList = null;
+    }
+
+    private void updateAnchorInfoForLayout(RecyclerView.Recycler recycler, RecyclerView.State state,
+            AnchorInfo anchorInfo) {
+        if (updateAnchorFromPendingData(state, anchorInfo)) {
+            if (DEBUG) {
+                Log.d(TAG, "updated anchor info from pending information");
+            }
+            return;
+        }
+
+        if (updateAnchorFromChildren(recycler, state, anchorInfo)) {
+            if (DEBUG) {
+                Log.d(TAG, "updated anchor info from existing children");
+            }
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "deciding anchor info for fresh state");
+        }
+        anchorInfo.assignCoordinateFromPadding();
+        anchorInfo.mPosition = mStackFromEnd ? state.getItemCount() - 1 : 0;
+    }
+
+    /**
+     * Finds an anchor child from existing Views. Most of the time, this is the view closest to
+     * start or end that has a valid position (e.g. not removed).
+     * <p>
+     * If a child has focus, it is given priority.
+     */
+    private boolean updateAnchorFromChildren(RecyclerView.Recycler recycler,
+            RecyclerView.State state, AnchorInfo anchorInfo) {
+        if (getChildCount() == 0) {
+            return false;
+        }
+        final View focused = getFocusedChild();
+        if (focused != null && anchorInfo.isViewValidAsAnchor(focused, state)) {
+            anchorInfo.assignFromViewAndKeepVisibleRect(focused);
+            return true;
+        }
+        if (mLastStackFromEnd != mStackFromEnd) {
+            return false;
+        }
+        View referenceChild = anchorInfo.mLayoutFromEnd
+                ? findReferenceChildClosestToEnd(recycler, state)
+                : findReferenceChildClosestToStart(recycler, state);
+        if (referenceChild != null) {
+            anchorInfo.assignFromView(referenceChild);
+            // If all visible views are removed in 1 pass, reference child might be out of bounds.
+            // If that is the case, offset it back to 0 so that we use these pre-layout children.
+            if (!state.isPreLayout() && supportsPredictiveItemAnimations()) {
+                // validate this child is at least partially visible. if not, offset it to start
+                final boolean notVisible =
+                        mOrientationHelper.getDecoratedStart(referenceChild) >= mOrientationHelper
+                                .getEndAfterPadding()
+                                || mOrientationHelper.getDecoratedEnd(referenceChild)
+                                < mOrientationHelper.getStartAfterPadding();
+                if (notVisible) {
+                    anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd
+                            ? mOrientationHelper.getEndAfterPadding()
+                            : mOrientationHelper.getStartAfterPadding();
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * If there is a pending scroll position or saved states, updates the anchor info from that
+     * data and returns true
+     */
+    private boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) {
+        if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) {
+            return false;
+        }
+        // validate scroll position
+        if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) {
+            mPendingScrollPosition = NO_POSITION;
+            mPendingScrollPositionOffset = INVALID_OFFSET;
+            if (DEBUG) {
+                Log.e(TAG, "ignoring invalid scroll position " + mPendingScrollPosition);
+            }
+            return false;
+        }
+
+        // if child is visible, try to make it a reference child and ensure it is fully visible.
+        // if child is not visible, align it depending on its virtual position.
+        anchorInfo.mPosition = mPendingScrollPosition;
+        if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) {
+            // Anchor offset depends on how that child was laid out. Here, we update it
+            // according to our current view bounds
+            anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
+            if (anchorInfo.mLayoutFromEnd) {
+                anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding()
+                        - mPendingSavedState.mAnchorOffset;
+            } else {
+                anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding()
+                        + mPendingSavedState.mAnchorOffset;
+            }
+            return true;
+        }
+
+        if (mPendingScrollPositionOffset == INVALID_OFFSET) {
+            View child = findViewByPosition(mPendingScrollPosition);
+            if (child != null) {
+                final int childSize = mOrientationHelper.getDecoratedMeasurement(child);
+                if (childSize > mOrientationHelper.getTotalSpace()) {
+                    // item does not fit. fix depending on layout direction
+                    anchorInfo.assignCoordinateFromPadding();
+                    return true;
+                }
+                final int startGap = mOrientationHelper.getDecoratedStart(child)
+                        - mOrientationHelper.getStartAfterPadding();
+                if (startGap < 0) {
+                    anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding();
+                    anchorInfo.mLayoutFromEnd = false;
+                    return true;
+                }
+                final int endGap = mOrientationHelper.getEndAfterPadding()
+                        - mOrientationHelper.getDecoratedEnd(child);
+                if (endGap < 0) {
+                    anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding();
+                    anchorInfo.mLayoutFromEnd = true;
+                    return true;
+                }
+                anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd
+                        ? (mOrientationHelper.getDecoratedEnd(child) + mOrientationHelper
+                                .getTotalSpaceChange())
+                        : mOrientationHelper.getDecoratedStart(child);
+            } else { // item is not visible.
+                if (getChildCount() > 0) {
+                    // get position of any child, does not matter
+                    int pos = getPosition(getChildAt(0));
+                    anchorInfo.mLayoutFromEnd = mPendingScrollPosition < pos
+                            == mShouldReverseLayout;
+                }
+                anchorInfo.assignCoordinateFromPadding();
+            }
+            return true;
+        }
+        // override layout from end values for consistency
+        anchorInfo.mLayoutFromEnd = mShouldReverseLayout;
+        // if this changes, we should update prepareForDrop as well
+        if (mShouldReverseLayout) {
+            anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding()
+                    - mPendingScrollPositionOffset;
+        } else {
+            anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding()
+                    + mPendingScrollPositionOffset;
+        }
+        return true;
+    }
+
+    /**
+     * @return The final offset amount for children
+     */
+    private int fixLayoutEndGap(int endOffset, RecyclerView.Recycler recycler,
+            RecyclerView.State state, boolean canOffsetChildren) {
+        int gap = mOrientationHelper.getEndAfterPadding() - endOffset;
+        int fixOffset = 0;
+        if (gap > 0) {
+            fixOffset = -scrollBy(-gap, recycler, state);
+        } else {
+            return 0; // nothing to fix
+        }
+        // move offset according to scroll amount
+        endOffset += fixOffset;
+        if (canOffsetChildren) {
+            // re-calculate gap, see if we could fix it
+            gap = mOrientationHelper.getEndAfterPadding() - endOffset;
+            if (gap > 0) {
+                mOrientationHelper.offsetChildren(gap);
+                return gap + fixOffset;
+            }
+        }
+        return fixOffset;
+    }
+
+    /**
+     * @return The final offset amount for children
+     */
+    private int fixLayoutStartGap(int startOffset, RecyclerView.Recycler recycler,
+            RecyclerView.State state, boolean canOffsetChildren) {
+        int gap = startOffset - mOrientationHelper.getStartAfterPadding();
+        int fixOffset = 0;
+        if (gap > 0) {
+            // check if we should fix this gap.
+            fixOffset = -scrollBy(gap, recycler, state);
+        } else {
+            return 0; // nothing to fix
+        }
+        startOffset += fixOffset;
+        if (canOffsetChildren) {
+            // re-calculate gap, see if we could fix it
+            gap = startOffset - mOrientationHelper.getStartAfterPadding();
+            if (gap > 0) {
+                mOrientationHelper.offsetChildren(-gap);
+                return fixOffset - gap;
+            }
+        }
+        return fixOffset;
+    }
+
+    private void updateLayoutStateToFillEnd(AnchorInfo anchorInfo) {
+        updateLayoutStateToFillEnd(anchorInfo.mPosition, anchorInfo.mCoordinate);
+    }
+
+    private void updateLayoutStateToFillEnd(int itemPosition, int offset) {
+        mLayoutState.mAvailable = mOrientationHelper.getEndAfterPadding() - offset;
+        mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD :
+                LayoutState.ITEM_DIRECTION_TAIL;
+        mLayoutState.mCurrentPosition = itemPosition;
+        mLayoutState.mLayoutDirection = LayoutState.LAYOUT_END;
+        mLayoutState.mOffset = offset;
+        mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
+    }
+
+    private void updateLayoutStateToFillStart(AnchorInfo anchorInfo) {
+        updateLayoutStateToFillStart(anchorInfo.mPosition, anchorInfo.mCoordinate);
+    }
+
+    private void updateLayoutStateToFillStart(int itemPosition, int offset) {
+        mLayoutState.mAvailable = offset - mOrientationHelper.getStartAfterPadding();
+        mLayoutState.mCurrentPosition = itemPosition;
+        mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL :
+                LayoutState.ITEM_DIRECTION_HEAD;
+        mLayoutState.mLayoutDirection = LayoutState.LAYOUT_START;
+        mLayoutState.mOffset = offset;
+        mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
+
+    }
+
+    protected boolean isLayoutRTL() {
+        return getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+    }
+
+    void ensureLayoutState() {
+        if (mLayoutState == null) {
+            mLayoutState = createLayoutState();
+        }
+        if (mOrientationHelper == null) {
+            mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation);
+        }
+    }
+
+    /**
+     * Test overrides this to plug some tracking and verification.
+     *
+     * @return A new LayoutState
+     */
+    LayoutState createLayoutState() {
+        return new LayoutState();
+    }
+
+    /**
+     * <p>Scroll the RecyclerView to make the position visible.</p>
+     *
+     * <p>RecyclerView will scroll the minimum amount that is necessary to make the
+     * target position visible. If you are looking for a similar behavior to
+     * {@link android.widget.ListView#setSelection(int)} or
+     * {@link android.widget.ListView#setSelectionFromTop(int, int)}, use
+     * {@link #scrollToPositionWithOffset(int, int)}.</p>
+     *
+     * <p>Note that scroll position change will not be reflected until the next layout call.</p>
+     *
+     * @param position Scroll to this adapter position
+     * @see #scrollToPositionWithOffset(int, int)
+     */
+    @Override
+    public void scrollToPosition(int position) {
+        mPendingScrollPosition = position;
+        mPendingScrollPositionOffset = INVALID_OFFSET;
+        if (mPendingSavedState != null) {
+            mPendingSavedState.invalidateAnchor();
+        }
+        requestLayout();
+    }
+
+    /**
+     * Scroll to the specified adapter position with the given offset from resolved layout
+     * start. Resolved layout start depends on {@link #getReverseLayout()},
+     * {@link View#getLayoutDirection()} and {@link #getStackFromEnd()}.
+     * <p>
+     * For example, if layout is {@link #VERTICAL} and {@link #getStackFromEnd()} is true, calling
+     * <code>scrollToPositionWithOffset(10, 20)</code> will layout such that
+     * <code>item[10]</code>'s bottom is 20 pixels above the RecyclerView's bottom.
+     * <p>
+     * Note that scroll position change will not be reflected until the next layout call.
+     * <p>
+     * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}.
+     *
+     * @param position Index (starting at 0) of the reference item.
+     * @param offset   The distance (in pixels) between the start edge of the item view and
+     *                 start edge of the RecyclerView.
+     * @see #setReverseLayout(boolean)
+     * @see #scrollToPosition(int)
+     */
+    public void scrollToPositionWithOffset(int position, int offset) {
+        mPendingScrollPosition = position;
+        mPendingScrollPositionOffset = offset;
+        if (mPendingSavedState != null) {
+            mPendingSavedState.invalidateAnchor();
+        }
+        requestLayout();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        if (mOrientation == VERTICAL) {
+            return 0;
+        }
+        return scrollBy(dx, recycler, state);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        if (mOrientation == HORIZONTAL) {
+            return 0;
+        }
+        return scrollBy(dy, recycler, state);
+    }
+
+    @Override
+    public int computeHorizontalScrollOffset(RecyclerView.State state) {
+        return computeScrollOffset(state);
+    }
+
+    @Override
+    public int computeVerticalScrollOffset(RecyclerView.State state) {
+        return computeScrollOffset(state);
+    }
+
+    @Override
+    public int computeHorizontalScrollExtent(RecyclerView.State state) {
+        return computeScrollExtent(state);
+    }
+
+    @Override
+    public int computeVerticalScrollExtent(RecyclerView.State state) {
+        return computeScrollExtent(state);
+    }
+
+    @Override
+    public int computeHorizontalScrollRange(RecyclerView.State state) {
+        return computeScrollRange(state);
+    }
+
+    @Override
+    public int computeVerticalScrollRange(RecyclerView.State state) {
+        return computeScrollRange(state);
+    }
+
+    private int computeScrollOffset(RecyclerView.State state) {
+        if (getChildCount() == 0) {
+            return 0;
+        }
+        ensureLayoutState();
+        return ScrollbarHelper.computeScrollOffset(state, mOrientationHelper,
+                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
+                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
+                this, mSmoothScrollbarEnabled, mShouldReverseLayout);
+    }
+
+    private int computeScrollExtent(RecyclerView.State state) {
+        if (getChildCount() == 0) {
+            return 0;
+        }
+        ensureLayoutState();
+        return ScrollbarHelper.computeScrollExtent(state, mOrientationHelper,
+                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
+                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
+                this,  mSmoothScrollbarEnabled);
+    }
+
+    private int computeScrollRange(RecyclerView.State state) {
+        if (getChildCount() == 0) {
+            return 0;
+        }
+        ensureLayoutState();
+        return ScrollbarHelper.computeScrollRange(state, mOrientationHelper,
+                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
+                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
+                this, mSmoothScrollbarEnabled);
+    }
+
+    /**
+     * When smooth scrollbar is enabled, the position and size of the scrollbar thumb is computed
+     * based on the number of visible pixels in the visible items. This however assumes that all
+     * list items have similar or equal widths or heights (depending on list orientation).
+     * If you use a list in which items have different dimensions, the scrollbar will change
+     * appearance as the user scrolls through the list. To avoid this issue,  you need to disable
+     * this property.
+     *
+     * When smooth scrollbar is disabled, the position and size of the scrollbar thumb is based
+     * solely on the number of items in the adapter and the position of the visible items inside
+     * the adapter. This provides a stable scrollbar as the user navigates through a list of items
+     * with varying widths / heights.
+     *
+     * @param enabled Whether or not to enable smooth scrollbar.
+     *
+     * @see #setSmoothScrollbarEnabled(boolean)
+     */
+    public void setSmoothScrollbarEnabled(boolean enabled) {
+        mSmoothScrollbarEnabled = enabled;
+    }
+
+    /**
+     * Returns the current state of the smooth scrollbar feature. It is enabled by default.
+     *
+     * @return True if smooth scrollbar is enabled, false otherwise.
+     *
+     * @see #setSmoothScrollbarEnabled(boolean)
+     */
+    public boolean isSmoothScrollbarEnabled() {
+        return mSmoothScrollbarEnabled;
+    }
+
+    private void updateLayoutState(int layoutDirection, int requiredSpace,
+            boolean canUseExistingSpace, RecyclerView.State state) {
+        // If parent provides a hint, don't measure unlimited.
+        mLayoutState.mInfinite = resolveIsInfinite();
+        mLayoutState.mExtra = getExtraLayoutSpace(state);
+        mLayoutState.mLayoutDirection = layoutDirection;
+        int scrollingOffset;
+        if (layoutDirection == LayoutState.LAYOUT_END) {
+            mLayoutState.mExtra += mOrientationHelper.getEndPadding();
+            // get the first child in the direction we are going
+            final View child = getChildClosestToEnd();
+            // the direction in which we are traversing children
+            mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
+                    : LayoutState.ITEM_DIRECTION_TAIL;
+            mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
+            mLayoutState.mOffset = mOrientationHelper.getDecoratedEnd(child);
+            // calculate how much we can scroll without adding new children (independent of layout)
+            scrollingOffset = mOrientationHelper.getDecoratedEnd(child)
+                    - mOrientationHelper.getEndAfterPadding();
+
+        } else {
+            final View child = getChildClosestToStart();
+            mLayoutState.mExtra += mOrientationHelper.getStartAfterPadding();
+            mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
+                    : LayoutState.ITEM_DIRECTION_HEAD;
+            mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection;
+            mLayoutState.mOffset = mOrientationHelper.getDecoratedStart(child);
+            scrollingOffset = -mOrientationHelper.getDecoratedStart(child)
+                    + mOrientationHelper.getStartAfterPadding();
+        }
+        mLayoutState.mAvailable = requiredSpace;
+        if (canUseExistingSpace) {
+            mLayoutState.mAvailable -= scrollingOffset;
+        }
+        mLayoutState.mScrollingOffset = scrollingOffset;
+    }
+
+    boolean resolveIsInfinite() {
+        return mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED
+                && mOrientationHelper.getEnd() == 0;
+    }
+
+    void collectPrefetchPositionsForLayoutState(RecyclerView.State state, LayoutState layoutState,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        final int pos = layoutState.mCurrentPosition;
+        if (pos >= 0 && pos < state.getItemCount()) {
+            layoutPrefetchRegistry.addPosition(pos, layoutState.mScrollingOffset);
+        }
+    }
+
+    @Override
+    public void collectInitialPrefetchPositions(int adapterItemCount,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        final boolean fromEnd;
+        final int anchorPos;
+        if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) {
+            // use restored state, since it hasn't been resolved yet
+            fromEnd = mPendingSavedState.mAnchorLayoutFromEnd;
+            anchorPos = mPendingSavedState.mAnchorPosition;
+        } else {
+            resolveShouldLayoutReverse();
+            fromEnd = mShouldReverseLayout;
+            if (mPendingScrollPosition == NO_POSITION) {
+                anchorPos = fromEnd ? adapterItemCount - 1 : 0;
+            } else {
+                anchorPos = mPendingScrollPosition;
+            }
+        }
+
+        final int direction = fromEnd
+                ? LayoutState.ITEM_DIRECTION_HEAD
+                : LayoutState.ITEM_DIRECTION_TAIL;
+        int targetPos = anchorPos;
+        for (int i = 0; i < mInitialItemPrefetchCount; i++) {
+            if (targetPos >= 0 && targetPos < adapterItemCount) {
+                layoutPrefetchRegistry.addPosition(targetPos, 0);
+            } else {
+                break; // no more to prefetch
+            }
+            targetPos += direction;
+        }
+    }
+
+    /**
+     * Sets the number of items to prefetch in
+     * {@link #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)}, which defines
+     * how many inner items should be prefetched when this LayoutManager's RecyclerView
+     * is nested inside another RecyclerView.
+     *
+     * <p>Set this value to the number of items this inner LayoutManager will display when it is
+     * first scrolled into the viewport. RecyclerView will attempt to prefetch that number of items
+     * so they are ready, avoiding jank as the inner RecyclerView is scrolled into the viewport.</p>
+     *
+     * <p>For example, take a vertically scrolling RecyclerView with horizontally scrolling inner
+     * RecyclerViews. The rows always have 4 items visible in them (or 5 if not aligned). Passing
+     * <code>4</code> to this method for each inner RecyclerView's LinearLayoutManager will enable
+     * RecyclerView's prefetching feature to do create/bind work for 4 views within a row early,
+     * before it is scrolled on screen, instead of just the default 2.</p>
+     *
+     * <p>Calling this method does nothing unless the LayoutManager is in a RecyclerView
+     * nested in another RecyclerView.</p>
+     *
+     * <p class="note"><strong>Note:</strong> Setting this value to be larger than the number of
+     * views that will be visible in this view can incur unnecessary bind work, and an increase to
+     * the number of Views created and in active use.</p>
+     *
+     * @param itemCount Number of items to prefetch
+     *
+     * @see #isItemPrefetchEnabled()
+     * @see #getInitialItemPrefetchCount()
+     * @see #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)
+     */
+    public void setInitialPrefetchItemCount(int itemCount) {
+        mInitialItemPrefetchCount = itemCount;
+    }
+
+    /**
+     * Gets the number of items to prefetch in
+     * {@link #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)}, which defines
+     * how many inner items should be prefetched when this LayoutManager's RecyclerView
+     * is nested inside another RecyclerView.
+     *
+     * @see #isItemPrefetchEnabled()
+     * @see #setInitialPrefetchItemCount(int)
+     * @see #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)
+     *
+     * @return number of items to prefetch.
+     */
+    public int getInitialItemPrefetchCount() {
+        return mInitialItemPrefetchCount;
+    }
+
+    @Override
+    public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        int delta = (mOrientation == HORIZONTAL) ? dx : dy;
+        if (getChildCount() == 0 || delta == 0) {
+            // can't support this scroll, so don't bother prefetching
+            return;
+        }
+
+        final int layoutDirection = delta > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
+        final int absDy = Math.abs(delta);
+        updateLayoutState(layoutDirection, absDy, true, state);
+        collectPrefetchPositionsForLayoutState(state, mLayoutState, layoutPrefetchRegistry);
+    }
+
+    int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
+        if (getChildCount() == 0 || dy == 0) {
+            return 0;
+        }
+        mLayoutState.mRecycle = true;
+        ensureLayoutState();
+        final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
+        final int absDy = Math.abs(dy);
+        updateLayoutState(layoutDirection, absDy, true, state);
+        final int consumed = mLayoutState.mScrollingOffset
+                + fill(recycler, mLayoutState, state, false);
+        if (consumed < 0) {
+            if (DEBUG) {
+                Log.d(TAG, "Don't have any more elements to scroll");
+            }
+            return 0;
+        }
+        final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
+        mOrientationHelper.offsetChildren(-scrolled);
+        if (DEBUG) {
+            Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);
+        }
+        mLayoutState.mLastScrollDelta = scrolled;
+        return scrolled;
+    }
+
+    @Override
+    public void assertNotInLayoutOrScroll(String message) {
+        if (mPendingSavedState == null) {
+            super.assertNotInLayoutOrScroll(message);
+        }
+    }
+
+    /**
+     * Recycles children between given indices.
+     *
+     * @param startIndex inclusive
+     * @param endIndex   exclusive
+     */
+    private void recycleChildren(RecyclerView.Recycler recycler, int startIndex, int endIndex) {
+        if (startIndex == endIndex) {
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Recycling " + Math.abs(startIndex - endIndex) + " items");
+        }
+        if (endIndex > startIndex) {
+            for (int i = endIndex - 1; i >= startIndex; i--) {
+                removeAndRecycleViewAt(i, recycler);
+            }
+        } else {
+            for (int i = startIndex; i > endIndex; i--) {
+                removeAndRecycleViewAt(i, recycler);
+            }
+        }
+    }
+
+    /**
+     * Recycles views that went out of bounds after scrolling towards the end of the layout.
+     * <p>
+     * Checks both layout position and visible position to guarantee that the view is not visible.
+     *
+     * @param recycler Recycler instance of {@link com.android.internal.widget.RecyclerView}
+     * @param dt       This can be used to add additional padding to the visible area. This is used
+     *                 to detect children that will go out of bounds after scrolling, without
+     *                 actually moving them.
+     */
+    private void recycleViewsFromStart(RecyclerView.Recycler recycler, int dt) {
+        if (dt < 0) {
+            if (DEBUG) {
+                Log.d(TAG, "Called recycle from start with a negative value. This might happen"
+                        + " during layout changes but may be sign of a bug");
+            }
+            return;
+        }
+        // ignore padding, ViewGroup may not clip children.
+        final int limit = dt;
+        final int childCount = getChildCount();
+        if (mShouldReverseLayout) {
+            for (int i = childCount - 1; i >= 0; i--) {
+                View child = getChildAt(i);
+                if (mOrientationHelper.getDecoratedEnd(child) > limit
+                        || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
+                    // stop here
+                    recycleChildren(recycler, childCount - 1, i);
+                    return;
+                }
+            }
+        } else {
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                if (mOrientationHelper.getDecoratedEnd(child) > limit
+                        || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
+                    // stop here
+                    recycleChildren(recycler, 0, i);
+                    return;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Recycles views that went out of bounds after scrolling towards the start of the layout.
+     * <p>
+     * Checks both layout position and visible position to guarantee that the view is not visible.
+     *
+     * @param recycler Recycler instance of {@link com.android.internal.widget.RecyclerView}
+     * @param dt       This can be used to add additional padding to the visible area. This is used
+     *                 to detect children that will go out of bounds after scrolling, without
+     *                 actually moving them.
+     */
+    private void recycleViewsFromEnd(RecyclerView.Recycler recycler, int dt) {
+        final int childCount = getChildCount();
+        if (dt < 0) {
+            if (DEBUG) {
+                Log.d(TAG, "Called recycle from end with a negative value. This might happen"
+                        + " during layout changes but may be sign of a bug");
+            }
+            return;
+        }
+        final int limit = mOrientationHelper.getEnd() - dt;
+        if (mShouldReverseLayout) {
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                if (mOrientationHelper.getDecoratedStart(child) < limit
+                        || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) {
+                    // stop here
+                    recycleChildren(recycler, 0, i);
+                    return;
+                }
+            }
+        } else {
+            for (int i = childCount - 1; i >= 0; i--) {
+                View child = getChildAt(i);
+                if (mOrientationHelper.getDecoratedStart(child) < limit
+                        || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) {
+                    // stop here
+                    recycleChildren(recycler, childCount - 1, i);
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method to call appropriate recycle method depending on current layout direction
+     *
+     * @param recycler    Current recycler that is attached to RecyclerView
+     * @param layoutState Current layout state. Right now, this object does not change but
+     *                    we may consider moving it out of this view so passing around as a
+     *                    parameter for now, rather than accessing {@link #mLayoutState}
+     * @see #recycleViewsFromStart(com.android.internal.widget.RecyclerView.Recycler, int)
+     * @see #recycleViewsFromEnd(com.android.internal.widget.RecyclerView.Recycler, int)
+     * @see com.android.internal.widget.LinearLayoutManager.LayoutState#mLayoutDirection
+     */
+    private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) {
+        if (!layoutState.mRecycle || layoutState.mInfinite) {
+            return;
+        }
+        if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
+            recycleViewsFromEnd(recycler, layoutState.mScrollingOffset);
+        } else {
+            recycleViewsFromStart(recycler, layoutState.mScrollingOffset);
+        }
+    }
+
+    /**
+     * The magic functions :). Fills the given layout, defined by the layoutState. This is fairly
+     * independent from the rest of the {@link com.android.internal.widget.LinearLayoutManager}
+     * and with little change, can be made publicly available as a helper class.
+     *
+     * @param recycler        Current recycler that is attached to RecyclerView
+     * @param layoutState     Configuration on how we should fill out the available space.
+     * @param state           Context passed by the RecyclerView to control scroll steps.
+     * @param stopOnFocusable If true, filling stops in the first focusable new child
+     * @return Number of pixels that it added. Useful for scroll functions.
+     */
+    int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
+            RecyclerView.State state, boolean stopOnFocusable) {
+        // max offset we should set is mFastScroll + available
+        final int start = layoutState.mAvailable;
+        if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
+            // TODO ugly bug fix. should not happen
+            if (layoutState.mAvailable < 0) {
+                layoutState.mScrollingOffset += layoutState.mAvailable;
+            }
+            recycleByLayoutState(recycler, layoutState);
+        }
+        int remainingSpace = layoutState.mAvailable + layoutState.mExtra;
+        LayoutChunkResult layoutChunkResult = mLayoutChunkResult;
+        while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
+            layoutChunkResult.resetInternal();
+            layoutChunk(recycler, state, layoutState, layoutChunkResult);
+            if (layoutChunkResult.mFinished) {
+                break;
+            }
+            layoutState.mOffset += layoutChunkResult.mConsumed * layoutState.mLayoutDirection;
+            /**
+             * Consume the available space if:
+             * * layoutChunk did not request to be ignored
+             * * OR we are laying out scrap children
+             * * OR we are not doing pre-layout
+             */
+            if (!layoutChunkResult.mIgnoreConsumed || mLayoutState.mScrapList != null
+                    || !state.isPreLayout()) {
+                layoutState.mAvailable -= layoutChunkResult.mConsumed;
+                // we keep a separate remaining space because mAvailable is important for recycling
+                remainingSpace -= layoutChunkResult.mConsumed;
+            }
+
+            if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
+                layoutState.mScrollingOffset += layoutChunkResult.mConsumed;
+                if (layoutState.mAvailable < 0) {
+                    layoutState.mScrollingOffset += layoutState.mAvailable;
+                }
+                recycleByLayoutState(recycler, layoutState);
+            }
+            if (stopOnFocusable && layoutChunkResult.mFocusable) {
+                break;
+            }
+        }
+        if (DEBUG) {
+            validateChildOrder();
+        }
+        return start - layoutState.mAvailable;
+    }
+
+    void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
+            LayoutState layoutState, LayoutChunkResult result) {
+        View view = layoutState.next(recycler);
+        if (view == null) {
+            if (DEBUG && layoutState.mScrapList == null) {
+                throw new RuntimeException("received null view when unexpected");
+            }
+            // if we are laying out views in scrap, this may return null which means there is
+            // no more items to layout.
+            result.mFinished = true;
+            return;
+        }
+        LayoutParams params = (LayoutParams) view.getLayoutParams();
+        if (layoutState.mScrapList == null) {
+            if (mShouldReverseLayout == (layoutState.mLayoutDirection
+                    == LayoutState.LAYOUT_START)) {
+                addView(view);
+            } else {
+                addView(view, 0);
+            }
+        } else {
+            if (mShouldReverseLayout == (layoutState.mLayoutDirection
+                    == LayoutState.LAYOUT_START)) {
+                addDisappearingView(view);
+            } else {
+                addDisappearingView(view, 0);
+            }
+        }
+        measureChildWithMargins(view, 0, 0);
+        result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view);
+        int left, top, right, bottom;
+        if (mOrientation == VERTICAL) {
+            if (isLayoutRTL()) {
+                right = getWidth() - getPaddingRight();
+                left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
+            } else {
+                left = getPaddingLeft();
+                right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
+            }
+            if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
+                bottom = layoutState.mOffset;
+                top = layoutState.mOffset - result.mConsumed;
+            } else {
+                top = layoutState.mOffset;
+                bottom = layoutState.mOffset + result.mConsumed;
+            }
+        } else {
+            top = getPaddingTop();
+            bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
+
+            if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
+                right = layoutState.mOffset;
+                left = layoutState.mOffset - result.mConsumed;
+            } else {
+                left = layoutState.mOffset;
+                right = layoutState.mOffset + result.mConsumed;
+            }
+        }
+        // We calculate everything with View's bounding box (which includes decor and margins)
+        // To calculate correct layout position, we subtract margins.
+        layoutDecoratedWithMargins(view, left, top, right, bottom);
+        if (DEBUG) {
+            Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:"
+                    + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:"
+                    + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin));
+        }
+        // Consume the available space if the view is not removed OR changed
+        if (params.isItemRemoved() || params.isItemChanged()) {
+            result.mIgnoreConsumed = true;
+        }
+        result.mFocusable = view.isFocusable();
+    }
+
+    @Override
+    boolean shouldMeasureTwice() {
+        return getHeightMode() != View.MeasureSpec.EXACTLY
+                && getWidthMode() != View.MeasureSpec.EXACTLY
+                && hasFlexibleChildInBothOrientations();
+    }
+
+    /**
+     * Converts a focusDirection to orientation.
+     *
+     * @param focusDirection One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+     *                       {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
+     *                       {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
+     *                       or 0 for not applicable
+     * @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction
+     * is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise.
+     */
+    int convertFocusDirectionToLayoutDirection(int focusDirection) {
+        switch (focusDirection) {
+            case View.FOCUS_BACKWARD:
+                if (mOrientation == VERTICAL) {
+                    return LayoutState.LAYOUT_START;
+                } else if (isLayoutRTL()) {
+                    return LayoutState.LAYOUT_END;
+                } else {
+                    return LayoutState.LAYOUT_START;
+                }
+            case View.FOCUS_FORWARD:
+                if (mOrientation == VERTICAL) {
+                    return LayoutState.LAYOUT_END;
+                } else if (isLayoutRTL()) {
+                    return LayoutState.LAYOUT_START;
+                } else {
+                    return LayoutState.LAYOUT_END;
+                }
+            case View.FOCUS_UP:
+                return mOrientation == VERTICAL ? LayoutState.LAYOUT_START
+                        : LayoutState.INVALID_LAYOUT;
+            case View.FOCUS_DOWN:
+                return mOrientation == VERTICAL ? LayoutState.LAYOUT_END
+                        : LayoutState.INVALID_LAYOUT;
+            case View.FOCUS_LEFT:
+                return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_START
+                        : LayoutState.INVALID_LAYOUT;
+            case View.FOCUS_RIGHT:
+                return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_END
+                        : LayoutState.INVALID_LAYOUT;
+            default:
+                if (DEBUG) {
+                    Log.d(TAG, "Unknown focus request:" + focusDirection);
+                }
+                return LayoutState.INVALID_LAYOUT;
+        }
+
+    }
+
+    /**
+     * Convenience method to find the child closes to start. Caller should check it has enough
+     * children.
+     *
+     * @return The child closes to start of the layout from user's perspective.
+     */
+    private View getChildClosestToStart() {
+        return getChildAt(mShouldReverseLayout ? getChildCount() - 1 : 0);
+    }
+
+    /**
+     * Convenience method to find the child closes to end. Caller should check it has enough
+     * children.
+     *
+     * @return The child closes to end of the layout from user's perspective.
+     */
+    private View getChildClosestToEnd() {
+        return getChildAt(mShouldReverseLayout ? 0 : getChildCount() - 1);
+    }
+
+    /**
+     * Convenience method to find the visible child closes to start. Caller should check if it has
+     * enough children.
+     *
+     * @param completelyVisible Whether child should be completely visible or not
+     * @return The first visible child closest to start of the layout from user's perspective.
+     */
+    private View findFirstVisibleChildClosestToStart(boolean completelyVisible,
+            boolean acceptPartiallyVisible) {
+        if (mShouldReverseLayout) {
+            return findOneVisibleChild(getChildCount() - 1, -1, completelyVisible,
+                    acceptPartiallyVisible);
+        } else {
+            return findOneVisibleChild(0, getChildCount(), completelyVisible,
+                    acceptPartiallyVisible);
+        }
+    }
+
+    /**
+     * Convenience method to find the visible child closes to end. Caller should check if it has
+     * enough children.
+     *
+     * @param completelyVisible Whether child should be completely visible or not
+     * @return The first visible child closest to end of the layout from user's perspective.
+     */
+    private View findFirstVisibleChildClosestToEnd(boolean completelyVisible,
+            boolean acceptPartiallyVisible) {
+        if (mShouldReverseLayout) {
+            return findOneVisibleChild(0, getChildCount(), completelyVisible,
+                    acceptPartiallyVisible);
+        } else {
+            return findOneVisibleChild(getChildCount() - 1, -1, completelyVisible,
+                    acceptPartiallyVisible);
+        }
+    }
+
+
+    /**
+     * Among the children that are suitable to be considered as an anchor child, returns the one
+     * closest to the end of the layout.
+     * <p>
+     * Due to ambiguous adapter updates or children being removed, some children's positions may be
+     * invalid. This method is a best effort to find a position within adapter bounds if possible.
+     * <p>
+     * It also prioritizes children that are within the visible bounds.
+     * @return A View that can be used an an anchor View.
+     */
+    private View findReferenceChildClosestToEnd(RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        return mShouldReverseLayout ? findFirstReferenceChild(recycler, state) :
+                findLastReferenceChild(recycler, state);
+    }
+
+    /**
+     * Among the children that are suitable to be considered as an anchor child, returns the one
+     * closest to the start of the layout.
+     * <p>
+     * Due to ambiguous adapter updates or children being removed, some children's positions may be
+     * invalid. This method is a best effort to find a position within adapter bounds if possible.
+     * <p>
+     * It also prioritizes children that are within the visible bounds.
+     *
+     * @return A View that can be used an an anchor View.
+     */
+    private View findReferenceChildClosestToStart(RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        return mShouldReverseLayout ? findLastReferenceChild(recycler, state) :
+                findFirstReferenceChild(recycler, state);
+    }
+
+    private View findFirstReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        return findReferenceChild(recycler, state, 0, getChildCount(), state.getItemCount());
+    }
+
+    private View findLastReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        return findReferenceChild(recycler, state, getChildCount() - 1, -1, state.getItemCount());
+    }
+
+    // overridden by GridLayoutManager
+    View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state,
+            int start, int end, int itemCount) {
+        ensureLayoutState();
+        View invalidMatch = null;
+        View outOfBoundsMatch = null;
+        final int boundsStart = mOrientationHelper.getStartAfterPadding();
+        final int boundsEnd = mOrientationHelper.getEndAfterPadding();
+        final int diff = end > start ? 1 : -1;
+        for (int i = start; i != end; i += diff) {
+            final View view = getChildAt(i);
+            final int position = getPosition(view);
+            if (position >= 0 && position < itemCount) {
+                if (((LayoutParams) view.getLayoutParams()).isItemRemoved()) {
+                    if (invalidMatch == null) {
+                        invalidMatch = view; // removed item, least preferred
+                    }
+                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd
+                        || mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
+                    if (outOfBoundsMatch == null) {
+                        outOfBoundsMatch = view; // item is not visible, less preferred
+                    }
+                } else {
+                    return view;
+                }
+            }
+        }
+        return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch;
+    }
+
+    /**
+     * Returns the adapter position of the first visible view. This position does not include
+     * adapter changes that were dispatched after the last layout pass.
+     * <p>
+     * Note that, this value is not affected by layout orientation or item order traversal.
+     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
+     * not in the layout.
+     * <p>
+     * If RecyclerView has item decorators, they will be considered in calculations as well.
+     * <p>
+     * LayoutManager may pre-cache some views that are not necessarily visible. Those views
+     * are ignored in this method.
+     *
+     * @return The adapter position of the first visible item or {@link RecyclerView#NO_POSITION} if
+     * there aren't any visible items.
+     * @see #findFirstCompletelyVisibleItemPosition()
+     * @see #findLastVisibleItemPosition()
+     */
+    public int findFirstVisibleItemPosition() {
+        final View child = findOneVisibleChild(0, getChildCount(), false, true);
+        return child == null ? NO_POSITION : getPosition(child);
+    }
+
+    /**
+     * Returns the adapter position of the first fully visible view. This position does not include
+     * adapter changes that were dispatched after the last layout pass.
+     * <p>
+     * Note that bounds check is only performed in the current orientation. That means, if
+     * LayoutManager is horizontal, it will only check the view's left and right edges.
+     *
+     * @return The adapter position of the first fully visible item or
+     * {@link RecyclerView#NO_POSITION} if there aren't any visible items.
+     * @see #findFirstVisibleItemPosition()
+     * @see #findLastCompletelyVisibleItemPosition()
+     */
+    public int findFirstCompletelyVisibleItemPosition() {
+        final View child = findOneVisibleChild(0, getChildCount(), true, false);
+        return child == null ? NO_POSITION : getPosition(child);
+    }
+
+    /**
+     * Returns the adapter position of the last visible view. This position does not include
+     * adapter changes that were dispatched after the last layout pass.
+     * <p>
+     * Note that, this value is not affected by layout orientation or item order traversal.
+     * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter,
+     * not in the layout.
+     * <p>
+     * If RecyclerView has item decorators, they will be considered in calculations as well.
+     * <p>
+     * LayoutManager may pre-cache some views that are not necessarily visible. Those views
+     * are ignored in this method.
+     *
+     * @return The adapter position of the last visible view or {@link RecyclerView#NO_POSITION} if
+     * there aren't any visible items.
+     * @see #findLastCompletelyVisibleItemPosition()
+     * @see #findFirstVisibleItemPosition()
+     */
+    public int findLastVisibleItemPosition() {
+        final View child = findOneVisibleChild(getChildCount() - 1, -1, false, true);
+        return child == null ? NO_POSITION : getPosition(child);
+    }
+
+    /**
+     * Returns the adapter position of the last fully visible view. This position does not include
+     * adapter changes that were dispatched after the last layout pass.
+     * <p>
+     * Note that bounds check is only performed in the current orientation. That means, if
+     * LayoutManager is horizontal, it will only check the view's left and right edges.
+     *
+     * @return The adapter position of the last fully visible view or
+     * {@link RecyclerView#NO_POSITION} if there aren't any visible items.
+     * @see #findLastVisibleItemPosition()
+     * @see #findFirstCompletelyVisibleItemPosition()
+     */
+    public int findLastCompletelyVisibleItemPosition() {
+        final View child = findOneVisibleChild(getChildCount() - 1, -1, true, false);
+        return child == null ? NO_POSITION : getPosition(child);
+    }
+
+    View findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible,
+            boolean acceptPartiallyVisible) {
+        ensureLayoutState();
+        final int start = mOrientationHelper.getStartAfterPadding();
+        final int end = mOrientationHelper.getEndAfterPadding();
+        final int next = toIndex > fromIndex ? 1 : -1;
+        View partiallyVisible = null;
+        for (int i = fromIndex; i != toIndex; i += next) {
+            final View child = getChildAt(i);
+            final int childStart = mOrientationHelper.getDecoratedStart(child);
+            final int childEnd = mOrientationHelper.getDecoratedEnd(child);
+            if (childStart < end && childEnd > start) {
+                if (completelyVisible) {
+                    if (childStart >= start && childEnd <= end) {
+                        return child;
+                    } else if (acceptPartiallyVisible && partiallyVisible == null) {
+                        partiallyVisible = child;
+                    }
+                } else {
+                    return child;
+                }
+            }
+        }
+        return partiallyVisible;
+    }
+
+    @Override
+    public View onFocusSearchFailed(View focused, int focusDirection,
+            RecyclerView.Recycler recycler, RecyclerView.State state) {
+        resolveShouldLayoutReverse();
+        if (getChildCount() == 0) {
+            return null;
+        }
+
+        final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection);
+        if (layoutDir == LayoutState.INVALID_LAYOUT) {
+            return null;
+        }
+        ensureLayoutState();
+        final View referenceChild;
+        if (layoutDir == LayoutState.LAYOUT_START) {
+            referenceChild = findReferenceChildClosestToStart(recycler, state);
+        } else {
+            referenceChild = findReferenceChildClosestToEnd(recycler, state);
+        }
+        if (referenceChild == null) {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "Cannot find a child with a valid position to be used for focus search.");
+            }
+            return null;
+        }
+        ensureLayoutState();
+        final int maxScroll = (int) (MAX_SCROLL_FACTOR * mOrientationHelper.getTotalSpace());
+        updateLayoutState(layoutDir, maxScroll, false, state);
+        mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
+        mLayoutState.mRecycle = false;
+        fill(recycler, mLayoutState, state, true);
+        final View nextFocus;
+        if (layoutDir == LayoutState.LAYOUT_START) {
+            nextFocus = getChildClosestToStart();
+        } else {
+            nextFocus = getChildClosestToEnd();
+        }
+        if (nextFocus == referenceChild || !nextFocus.isFocusable()) {
+            return null;
+        }
+        return nextFocus;
+    }
+
+    /**
+     * Used for debugging.
+     * Logs the internal representation of children to default logger.
+     */
+    private void logChildren() {
+        Log.d(TAG, "internal representation of views on the screen");
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            Log.d(TAG, "item " + getPosition(child) + ", coord:"
+                    + mOrientationHelper.getDecoratedStart(child));
+        }
+        Log.d(TAG, "==============");
+    }
+
+    /**
+     * Used for debugging.
+     * Validates that child views are laid out in correct order. This is important because rest of
+     * the algorithm relies on this constraint.
+     *
+     * In default layout, child 0 should be closest to screen position 0 and last child should be
+     * closest to position WIDTH or HEIGHT.
+     * In reverse layout, last child should be closes to screen position 0 and first child should
+     * be closest to position WIDTH  or HEIGHT
+     */
+    void validateChildOrder() {
+        Log.d(TAG, "validating child count " + getChildCount());
+        if (getChildCount() < 1) {
+            return;
+        }
+        int lastPos = getPosition(getChildAt(0));
+        int lastScreenLoc = mOrientationHelper.getDecoratedStart(getChildAt(0));
+        if (mShouldReverseLayout) {
+            for (int i = 1; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                int pos = getPosition(child);
+                int screenLoc = mOrientationHelper.getDecoratedStart(child);
+                if (pos < lastPos) {
+                    logChildren();
+                    throw new RuntimeException("detected invalid position. loc invalid? "
+                            + (screenLoc < lastScreenLoc));
+                }
+                if (screenLoc > lastScreenLoc) {
+                    logChildren();
+                    throw new RuntimeException("detected invalid location");
+                }
+            }
+        } else {
+            for (int i = 1; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                int pos = getPosition(child);
+                int screenLoc = mOrientationHelper.getDecoratedStart(child);
+                if (pos < lastPos) {
+                    logChildren();
+                    throw new RuntimeException("detected invalid position. loc invalid? "
+                            + (screenLoc < lastScreenLoc));
+                }
+                if (screenLoc < lastScreenLoc) {
+                    logChildren();
+                    throw new RuntimeException("detected invalid location");
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean supportsPredictiveItemAnimations() {
+        return mPendingSavedState == null && mLastStackFromEnd == mStackFromEnd;
+    }
+
+    /**
+     * @hide This method should be called by ItemTouchHelper only.
+     */
+    @Override
+    public void prepareForDrop(View view, View target, int x, int y) {
+        assertNotInLayoutOrScroll("Cannot drop a view during a scroll or layout calculation");
+        ensureLayoutState();
+        resolveShouldLayoutReverse();
+        final int myPos = getPosition(view);
+        final int targetPos = getPosition(target);
+        final int dropDirection = myPos < targetPos ? LayoutState.ITEM_DIRECTION_TAIL
+                : LayoutState.ITEM_DIRECTION_HEAD;
+        if (mShouldReverseLayout) {
+            if (dropDirection == LayoutState.ITEM_DIRECTION_TAIL) {
+                scrollToPositionWithOffset(targetPos,
+                        mOrientationHelper.getEndAfterPadding()
+                                - (mOrientationHelper.getDecoratedStart(target)
+                                        + mOrientationHelper.getDecoratedMeasurement(view)));
+            } else {
+                scrollToPositionWithOffset(targetPos,
+                        mOrientationHelper.getEndAfterPadding()
+                                - mOrientationHelper.getDecoratedEnd(target));
+            }
+        } else {
+            if (dropDirection == LayoutState.ITEM_DIRECTION_HEAD) {
+                scrollToPositionWithOffset(targetPos, mOrientationHelper.getDecoratedStart(target));
+            } else {
+                scrollToPositionWithOffset(targetPos,
+                        mOrientationHelper.getDecoratedEnd(target)
+                                - mOrientationHelper.getDecoratedMeasurement(view));
+            }
+        }
+    }
+
+    /**
+     * Helper class that keeps temporary state while {LayoutManager} is filling out the empty
+     * space.
+     */
+    static class LayoutState {
+
+        static final String TAG = "LLM#LayoutState";
+
+        static final int LAYOUT_START = -1;
+
+        static final int LAYOUT_END = 1;
+
+        static final int INVALID_LAYOUT = Integer.MIN_VALUE;
+
+        static final int ITEM_DIRECTION_HEAD = -1;
+
+        static final int ITEM_DIRECTION_TAIL = 1;
+
+        static final int SCROLLING_OFFSET_NaN = Integer.MIN_VALUE;
+
+        /**
+         * We may not want to recycle children in some cases (e.g. layout)
+         */
+        boolean mRecycle = true;
+
+        /**
+         * Pixel offset where layout should start
+         */
+        int mOffset;
+
+        /**
+         * Number of pixels that we should fill, in the layout direction.
+         */
+        int mAvailable;
+
+        /**
+         * Current position on the adapter to get the next item.
+         */
+        int mCurrentPosition;
+
+        /**
+         * Defines the direction in which the data adapter is traversed.
+         * Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL}
+         */
+        int mItemDirection;
+
+        /**
+         * Defines the direction in which the layout is filled.
+         * Should be {@link #LAYOUT_START} or {@link #LAYOUT_END}
+         */
+        int mLayoutDirection;
+
+        /**
+         * Used when LayoutState is constructed in a scrolling state.
+         * It should be set the amount of scrolling we can make without creating a new view.
+         * Settings this is required for efficient view recycling.
+         */
+        int mScrollingOffset;
+
+        /**
+         * Used if you want to pre-layout items that are not yet visible.
+         * The difference with {@link #mAvailable} is that, when recycling, distance laid out for
+         * {@link #mExtra} is not considered to avoid recycling visible children.
+         */
+        int mExtra = 0;
+
+        /**
+         * Equal to {@link RecyclerView.State#isPreLayout()}. When consuming scrap, if this value
+         * is set to true, we skip removed views since they should not be laid out in post layout
+         * step.
+         */
+        boolean mIsPreLayout = false;
+
+        /**
+         * The most recent {@link #scrollBy(int, RecyclerView.Recycler, RecyclerView.State)}
+         * amount.
+         */
+        int mLastScrollDelta;
+
+        /**
+         * When LLM needs to layout particular views, it sets this list in which case, LayoutState
+         * will only return views from this list and return null if it cannot find an item.
+         */
+        List<RecyclerView.ViewHolder> mScrapList = null;
+
+        /**
+         * Used when there is no limit in how many views can be laid out.
+         */
+        boolean mInfinite;
+
+        /**
+         * @return true if there are more items in the data adapter
+         */
+        boolean hasMore(RecyclerView.State state) {
+            return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount();
+        }
+
+        /**
+         * Gets the view for the next element that we should layout.
+         * Also updates current item index to the next item, based on {@link #mItemDirection}
+         *
+         * @return The next element that we should layout.
+         */
+        View next(RecyclerView.Recycler recycler) {
+            if (mScrapList != null) {
+                return nextViewFromScrapList();
+            }
+            final View view = recycler.getViewForPosition(mCurrentPosition);
+            mCurrentPosition += mItemDirection;
+            return view;
+        }
+
+        /**
+         * Returns the next item from the scrap list.
+         * <p>
+         * Upon finding a valid VH, sets current item position to VH.itemPosition + mItemDirection
+         *
+         * @return View if an item in the current position or direction exists if not null.
+         */
+        private View nextViewFromScrapList() {
+            final int size = mScrapList.size();
+            for (int i = 0; i < size; i++) {
+                final View view = mScrapList.get(i).itemView;
+                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                if (lp.isItemRemoved()) {
+                    continue;
+                }
+                if (mCurrentPosition == lp.getViewLayoutPosition()) {
+                    assignPositionFromScrapList(view);
+                    return view;
+                }
+            }
+            return null;
+        }
+
+        public void assignPositionFromScrapList() {
+            assignPositionFromScrapList(null);
+        }
+
+        public void assignPositionFromScrapList(View ignore) {
+            final View closest = nextViewInLimitedList(ignore);
+            if (closest == null) {
+                mCurrentPosition = NO_POSITION;
+            } else {
+                mCurrentPosition = ((LayoutParams) closest.getLayoutParams())
+                        .getViewLayoutPosition();
+            }
+        }
+
+        public View nextViewInLimitedList(View ignore) {
+            int size = mScrapList.size();
+            View closest = null;
+            int closestDistance = Integer.MAX_VALUE;
+            if (DEBUG && mIsPreLayout) {
+                throw new IllegalStateException("Scrap list cannot be used in pre layout");
+            }
+            for (int i = 0; i < size; i++) {
+                View view = mScrapList.get(i).itemView;
+                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                if (view == ignore || lp.isItemRemoved()) {
+                    continue;
+                }
+                final int distance = (lp.getViewLayoutPosition() - mCurrentPosition)
+                        * mItemDirection;
+                if (distance < 0) {
+                    continue; // item is not in current direction
+                }
+                if (distance < closestDistance) {
+                    closest = view;
+                    closestDistance = distance;
+                    if (distance == 0) {
+                        break;
+                    }
+                }
+            }
+            return closest;
+        }
+
+        void log() {
+            Log.d(TAG, "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:"
+                    + mItemDirection + ", offset:" + mOffset + ", layoutDir:" + mLayoutDirection);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static class SavedState implements Parcelable {
+
+        int mAnchorPosition;
+
+        int mAnchorOffset;
+
+        boolean mAnchorLayoutFromEnd;
+
+        public SavedState() {
+
+        }
+
+        SavedState(Parcel in) {
+            mAnchorPosition = in.readInt();
+            mAnchorOffset = in.readInt();
+            mAnchorLayoutFromEnd = in.readInt() == 1;
+        }
+
+        public SavedState(SavedState other) {
+            mAnchorPosition = other.mAnchorPosition;
+            mAnchorOffset = other.mAnchorOffset;
+            mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd;
+        }
+
+        boolean hasValidAnchor() {
+            return mAnchorPosition >= 0;
+        }
+
+        void invalidateAnchor() {
+            mAnchorPosition = NO_POSITION;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mAnchorPosition);
+            dest.writeInt(mAnchorOffset);
+            dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+                    @Override
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in);
+                    }
+
+                    @Override
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
+    }
+
+    /**
+     * Simple data class to keep Anchor information
+     */
+    class AnchorInfo {
+        int mPosition;
+        int mCoordinate;
+        boolean mLayoutFromEnd;
+        boolean mValid;
+
+        AnchorInfo() {
+            reset();
+        }
+
+        void reset() {
+            mPosition = NO_POSITION;
+            mCoordinate = INVALID_OFFSET;
+            mLayoutFromEnd = false;
+            mValid = false;
+        }
+
+        /**
+         * assigns anchor coordinate from the RecyclerView's padding depending on current
+         * layoutFromEnd value
+         */
+        void assignCoordinateFromPadding() {
+            mCoordinate = mLayoutFromEnd
+                    ? mOrientationHelper.getEndAfterPadding()
+                    : mOrientationHelper.getStartAfterPadding();
+        }
+
+        @Override
+        public String toString() {
+            return "AnchorInfo{"
+                    + "mPosition=" + mPosition
+                    + ", mCoordinate=" + mCoordinate
+                    + ", mLayoutFromEnd=" + mLayoutFromEnd
+                    + ", mValid=" + mValid
+                    + '}';
+        }
+
+        boolean isViewValidAsAnchor(View child, RecyclerView.State state) {
+            LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            return !lp.isItemRemoved() && lp.getViewLayoutPosition() >= 0
+                    && lp.getViewLayoutPosition() < state.getItemCount();
+        }
+
+        public void assignFromViewAndKeepVisibleRect(View child) {
+            final int spaceChange = mOrientationHelper.getTotalSpaceChange();
+            if (spaceChange >= 0) {
+                assignFromView(child);
+                return;
+            }
+            mPosition = getPosition(child);
+            if (mLayoutFromEnd) {
+                final int prevLayoutEnd = mOrientationHelper.getEndAfterPadding() - spaceChange;
+                final int childEnd = mOrientationHelper.getDecoratedEnd(child);
+                final int previousEndMargin = prevLayoutEnd - childEnd;
+                mCoordinate = mOrientationHelper.getEndAfterPadding() - previousEndMargin;
+                // ensure we did not push child's top out of bounds because of this
+                if (previousEndMargin > 0) { // we have room to shift bottom if necessary
+                    final int childSize = mOrientationHelper.getDecoratedMeasurement(child);
+                    final int estimatedChildStart = mCoordinate - childSize;
+                    final int layoutStart = mOrientationHelper.getStartAfterPadding();
+                    final int previousStartMargin = mOrientationHelper.getDecoratedStart(child)
+                            - layoutStart;
+                    final int startReference = layoutStart + Math.min(previousStartMargin, 0);
+                    final int startMargin = estimatedChildStart - startReference;
+                    if (startMargin < 0) {
+                        // offset to make top visible but not too much
+                        mCoordinate += Math.min(previousEndMargin, -startMargin);
+                    }
+                }
+            } else {
+                final int childStart = mOrientationHelper.getDecoratedStart(child);
+                final int startMargin = childStart - mOrientationHelper.getStartAfterPadding();
+                mCoordinate = childStart;
+                if (startMargin > 0) { // we have room to fix end as well
+                    final int estimatedEnd = childStart
+                            + mOrientationHelper.getDecoratedMeasurement(child);
+                    final int previousLayoutEnd = mOrientationHelper.getEndAfterPadding()
+                            - spaceChange;
+                    final int previousEndMargin = previousLayoutEnd
+                            - mOrientationHelper.getDecoratedEnd(child);
+                    final int endReference = mOrientationHelper.getEndAfterPadding()
+                            - Math.min(0, previousEndMargin);
+                    final int endMargin = endReference - estimatedEnd;
+                    if (endMargin < 0) {
+                        mCoordinate -= Math.min(startMargin, -endMargin);
+                    }
+                }
+            }
+        }
+
+        public void assignFromView(View child) {
+            if (mLayoutFromEnd) {
+                mCoordinate = mOrientationHelper.getDecoratedEnd(child)
+                        + mOrientationHelper.getTotalSpaceChange();
+            } else {
+                mCoordinate = mOrientationHelper.getDecoratedStart(child);
+            }
+
+            mPosition = getPosition(child);
+        }
+    }
+
+    protected static class LayoutChunkResult {
+        public int mConsumed;
+        public boolean mFinished;
+        public boolean mIgnoreConsumed;
+        public boolean mFocusable;
+
+        void resetInternal() {
+            mConsumed = 0;
+            mFinished = false;
+            mIgnoreConsumed = false;
+            mFocusable = false;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/LinearSmoothScroller.java b/core/java/com/android/internal/widget/LinearSmoothScroller.java
new file mode 100644
index 0000000..d024f21
--- /dev/null
+++ b/core/java/com/android/internal/widget/LinearSmoothScroller.java
@@ -0,0 +1,361 @@
+/*
+ * 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.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.PointF;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * {@link RecyclerView.SmoothScroller} implementation which uses a {@link LinearInterpolator} until
+ * the target position becomes a child of the RecyclerView and then uses a
+ * {@link DecelerateInterpolator} to slowly approach to target position.
+ * <p>
+ * If the {@link RecyclerView.LayoutManager} you are using does not implement the
+ * {@link RecyclerView.SmoothScroller.ScrollVectorProvider} interface, then you must override the
+ * {@link #computeScrollVectorForPosition(int)} method. All the LayoutManagers bundled with
+ * the support library implement this interface.
+ */
+public class LinearSmoothScroller extends RecyclerView.SmoothScroller {
+
+    private static final String TAG = "LinearSmoothScroller";
+
+    private static final boolean DEBUG = false;
+
+    private static final float MILLISECONDS_PER_INCH = 25f;
+
+    private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000;
+
+    /**
+     * Align child view's left or top with parent view's left or top
+     *
+     * @see #calculateDtToFit(int, int, int, int, int)
+     * @see #calculateDxToMakeVisible(android.view.View, int)
+     * @see #calculateDyToMakeVisible(android.view.View, int)
+     */
+    public static final int SNAP_TO_START = -1;
+
+    /**
+     * Align child view's right or bottom with parent view's right or bottom
+     *
+     * @see #calculateDtToFit(int, int, int, int, int)
+     * @see #calculateDxToMakeVisible(android.view.View, int)
+     * @see #calculateDyToMakeVisible(android.view.View, int)
+     */
+    public static final int SNAP_TO_END = 1;
+
+    /**
+     * <p>Decides if the child should be snapped from start or end, depending on where it
+     * currently is in relation to its parent.</p>
+     * <p>For instance, if the view is virtually on the left of RecyclerView, using
+     * {@code SNAP_TO_ANY} is the same as using {@code SNAP_TO_START}</p>
+     *
+     * @see #calculateDtToFit(int, int, int, int, int)
+     * @see #calculateDxToMakeVisible(android.view.View, int)
+     * @see #calculateDyToMakeVisible(android.view.View, int)
+     */
+    public static final int SNAP_TO_ANY = 0;
+
+    // Trigger a scroll to a further distance than TARGET_SEEK_SCROLL_DISTANCE_PX so that if target
+    // view is not laid out until interim target position is reached, we can detect the case before
+    // scrolling slows down and reschedule another interim target scroll
+    private static final float TARGET_SEEK_EXTRA_SCROLL_RATIO = 1.2f;
+
+    protected final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
+
+    protected final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator();
+
+    protected PointF mTargetVector;
+
+    private final float MILLISECONDS_PER_PX;
+
+    // Temporary variables to keep track of the interim scroll target. These values do not
+    // point to a real item position, rather point to an estimated location pixels.
+    protected int mInterimTargetDx = 0, mInterimTargetDy = 0;
+
+    public LinearSmoothScroller(Context context) {
+        MILLISECONDS_PER_PX = calculateSpeedPerPixel(context.getResources().getDisplayMetrics());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void onStart() {
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
+        final int dx = calculateDxToMakeVisible(targetView, getHorizontalSnapPreference());
+        final int dy = calculateDyToMakeVisible(targetView, getVerticalSnapPreference());
+        final int distance = (int) Math.sqrt(dx * dx + dy * dy);
+        final int time = calculateTimeForDeceleration(distance);
+        if (time > 0) {
+            action.update(-dx, -dy, time, mDecelerateInterpolator);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state, Action action) {
+        if (getChildCount() == 0) {
+            stop();
+            return;
+        }
+        //noinspection PointlessBooleanExpression
+        if (DEBUG && mTargetVector != null
+                && ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) {
+            throw new IllegalStateException("Scroll happened in the opposite direction"
+                    + " of the target. Some calculations are wrong");
+        }
+        mInterimTargetDx = clampApplyScroll(mInterimTargetDx, dx);
+        mInterimTargetDy = clampApplyScroll(mInterimTargetDy, dy);
+
+        if (mInterimTargetDx == 0 && mInterimTargetDy == 0) {
+            updateActionForInterimTarget(action);
+        } // everything is valid, keep going
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void onStop() {
+        mInterimTargetDx = mInterimTargetDy = 0;
+        mTargetVector = null;
+    }
+
+    /**
+     * Calculates the scroll speed.
+     *
+     * @param displayMetrics DisplayMetrics to be used for real dimension calculations
+     * @return The time (in ms) it should take for each pixel. For instance, if returned value is
+     * 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
+     */
+    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
+        return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
+    }
+
+    /**
+     * <p>Calculates the time for deceleration so that transition from LinearInterpolator to
+     * DecelerateInterpolator looks smooth.</p>
+     *
+     * @param dx Distance to scroll
+     * @return Time for DecelerateInterpolator to smoothly traverse the distance when transitioning
+     * from LinearInterpolation
+     */
+    protected int calculateTimeForDeceleration(int dx) {
+        // we want to cover same area with the linear interpolator for the first 10% of the
+        // interpolation. After that, deceleration will take control.
+        // area under curve (1-(1-x)^2) can be calculated as (1 - x/3) * x * x
+        // which gives 0.100028 when x = .3356
+        // this is why we divide linear scrolling time with .3356
+        return  (int) Math.ceil(calculateTimeForScrolling(dx) / .3356);
+    }
+
+    /**
+     * Calculates the time it should take to scroll the given distance (in pixels)
+     *
+     * @param dx Distance in pixels that we want to scroll
+     * @return Time in milliseconds
+     * @see #calculateSpeedPerPixel(android.util.DisplayMetrics)
+     */
+    protected int calculateTimeForScrolling(int dx) {
+        // In a case where dx is very small, rounding may return 0 although dx > 0.
+        // To avoid that issue, ceil the result so that if dx > 0, we'll always return positive
+        // time.
+        return (int) Math.ceil(Math.abs(dx) * MILLISECONDS_PER_PX);
+    }
+
+    /**
+     * When scrolling towards a child view, this method defines whether we should align the left
+     * or the right edge of the child with the parent RecyclerView.
+     *
+     * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
+     * @see #SNAP_TO_START
+     * @see #SNAP_TO_END
+     * @see #SNAP_TO_ANY
+     */
+    protected int getHorizontalSnapPreference() {
+        return mTargetVector == null || mTargetVector.x == 0 ? SNAP_TO_ANY :
+                mTargetVector.x > 0 ? SNAP_TO_END : SNAP_TO_START;
+    }
+
+    /**
+     * When scrolling towards a child view, this method defines whether we should align the top
+     * or the bottom edge of the child with the parent RecyclerView.
+     *
+     * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
+     * @see #SNAP_TO_START
+     * @see #SNAP_TO_END
+     * @see #SNAP_TO_ANY
+     */
+    protected int getVerticalSnapPreference() {
+        return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
+                mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
+    }
+
+    /**
+     * When the target scroll position is not a child of the RecyclerView, this method calculates
+     * a direction vector towards that child and triggers a smooth scroll.
+     *
+     * @see #computeScrollVectorForPosition(int)
+     */
+    protected void updateActionForInterimTarget(Action action) {
+        // find an interim target position
+        PointF scrollVector = computeScrollVectorForPosition(getTargetPosition());
+        if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) {
+            final int target = getTargetPosition();
+            action.jumpTo(target);
+            stop();
+            return;
+        }
+        normalize(scrollVector);
+        mTargetVector = scrollVector;
+
+        mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x);
+        mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y);
+        final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX);
+        // To avoid UI hiccups, trigger a smooth scroll to a distance little further than the
+        // interim target. Since we track the distance travelled in onSeekTargetStep callback, it
+        // won't actually scroll more than what we need.
+        action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO),
+                (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO),
+                (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator);
+    }
+
+    private int clampApplyScroll(int tmpDt, int dt) {
+        final int before = tmpDt;
+        tmpDt -= dt;
+        if (before * tmpDt <= 0) { // changed sign, reached 0 or was 0, reset
+            return 0;
+        }
+        return tmpDt;
+    }
+
+    /**
+     * Helper method for {@link #calculateDxToMakeVisible(android.view.View, int)} and
+     * {@link #calculateDyToMakeVisible(android.view.View, int)}
+     */
+    public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int
+            snapPreference) {
+        switch (snapPreference) {
+            case SNAP_TO_START:
+                return boxStart - viewStart;
+            case SNAP_TO_END:
+                return boxEnd - viewEnd;
+            case SNAP_TO_ANY:
+                final int dtStart = boxStart - viewStart;
+                if (dtStart > 0) {
+                    return dtStart;
+                }
+                final int dtEnd = boxEnd - viewEnd;
+                if (dtEnd < 0) {
+                    return dtEnd;
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("snap preference should be one of the"
+                        + " constants defined in SmoothScroller, starting with SNAP_");
+        }
+        return 0;
+    }
+
+    /**
+     * Calculates the vertical scroll amount necessary to make the given view fully visible
+     * inside the RecyclerView.
+     *
+     * @param view           The view which we want to make fully visible
+     * @param snapPreference The edge which the view should snap to when entering the visible
+     *                       area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
+     *                       {@link #SNAP_TO_ANY}.
+     * @return The vertical scroll amount necessary to make the view visible with the given
+     * snap preference.
+     */
+    public int calculateDyToMakeVisible(View view, int snapPreference) {
+        final RecyclerView.LayoutManager layoutManager = getLayoutManager();
+        if (layoutManager == null || !layoutManager.canScrollVertically()) {
+            return 0;
+        }
+        final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                view.getLayoutParams();
+        final int top = layoutManager.getDecoratedTop(view) - params.topMargin;
+        final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin;
+        final int start = layoutManager.getPaddingTop();
+        final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom();
+        return calculateDtToFit(top, bottom, start, end, snapPreference);
+    }
+
+    /**
+     * Calculates the horizontal scroll amount necessary to make the given view fully visible
+     * inside the RecyclerView.
+     *
+     * @param view           The view which we want to make fully visible
+     * @param snapPreference The edge which the view should snap to when entering the visible
+     *                       area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or
+     *                       {@link #SNAP_TO_END}
+     * @return The vertical scroll amount necessary to make the view visible with the given
+     * snap preference.
+     */
+    public int calculateDxToMakeVisible(View view, int snapPreference) {
+        final RecyclerView.LayoutManager layoutManager = getLayoutManager();
+        if (layoutManager == null || !layoutManager.canScrollHorizontally()) {
+            return 0;
+        }
+        final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                view.getLayoutParams();
+        final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin;
+        final int right = layoutManager.getDecoratedRight(view) + params.rightMargin;
+        final int start = layoutManager.getPaddingLeft();
+        final int end = layoutManager.getWidth() - layoutManager.getPaddingRight();
+        return calculateDtToFit(left, right, start, end, snapPreference);
+    }
+
+    /**
+     * Compute the scroll vector for a given target position.
+     * <p>
+     * This method can return null if the layout manager cannot calculate a scroll vector
+     * for the given position (e.g. it has no current scroll position).
+     *
+     * @param targetPosition the position to which the scroller is scrolling
+     *
+     * @return the scroll vector for a given target position
+     */
+    @Nullable
+    public PointF computeScrollVectorForPosition(int targetPosition) {
+        RecyclerView.LayoutManager layoutManager = getLayoutManager();
+        if (layoutManager instanceof ScrollVectorProvider) {
+            return ((ScrollVectorProvider) layoutManager)
+                    .computeScrollVectorForPosition(targetPosition);
+        }
+        Log.w(TAG, "You should override computeScrollVectorForPosition when the LayoutManager"
+                + " does not implement " + ScrollVectorProvider.class.getCanonicalName());
+        return null;
+    }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a43f3a7..ece5540 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -298,6 +298,10 @@
         getTrustManager().reportUnlockAttempt(true /* authenticated */, userId);
     }
 
+    public void reportPasswordLockout(int timeoutMs, int userId) {
+        getTrustManager().reportUnlockLockout(timeoutMs, userId);
+    }
+
     public int getCurrentFailedPasswordAttempts(int userId) {
         return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
     }
@@ -1310,7 +1314,7 @@
     }
 
     private boolean isDoNotAskCredentialsOnBootSet() {
-        return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
+        return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
     }
 
     private boolean shouldEncryptWithCredentials(boolean defaultValue) {
diff --git a/core/java/com/android/internal/widget/NestedScrollingChild.java b/core/java/com/android/internal/widget/NestedScrollingChild.java
new file mode 100644
index 0000000..20285b5
--- /dev/null
+++ b/core/java/com/android/internal/widget/NestedScrollingChild.java
@@ -0,0 +1,226 @@
+/*
+ * 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.widget;
+
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
+
+/**
+ * This interface should be implemented by {@link android.view.View View} subclasses that wish
+ * to support dispatching nested scrolling operations to a cooperating parent
+ * {@link android.view.ViewGroup ViewGroup}.
+ *
+ * <p>Classes implementing this interface should create a final instance of a
+ * {@link NestedScrollingChildHelper} as a field and delegate any View methods to the
+ * <code>NestedScrollingChildHelper</code> methods of the same signature.</p>
+ *
+ * <p>Views invoking nested scrolling functionality should always do so from the relevant
+ * {@link ViewCompat}, {@link ViewGroupCompat} or {@link ViewParentCompat} compatibility
+ * shim static methods. This ensures interoperability with nested scrolling views on Android
+ * 5.0 Lollipop and newer.</p>
+ */
+public interface NestedScrollingChild {
+    /**
+     * Enable or disable nested scrolling for this view.
+     *
+     * <p>If this property is set to true the view will be permitted to initiate nested
+     * scrolling operations with a compatible parent view in the current hierarchy. If this
+     * view does not implement nested scrolling this will have no effect. Disabling nested scrolling
+     * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping}
+     * the nested scroll.</p>
+     *
+     * @param enabled true to enable nested scrolling, false to disable
+     *
+     * @see #isNestedScrollingEnabled()
+     */
+    void setNestedScrollingEnabled(boolean enabled);
+
+    /**
+     * Returns true if nested scrolling is enabled for this view.
+     *
+     * <p>If nested scrolling is enabled and this View class implementation supports it,
+     * this view will act as a nested scrolling child view when applicable, forwarding data
+     * about the scroll operation in progress to a compatible and cooperating nested scrolling
+     * parent.</p>
+     *
+     * @return true if nested scrolling is enabled
+     *
+     * @see #setNestedScrollingEnabled(boolean)
+     */
+    boolean isNestedScrollingEnabled();
+
+    /**
+     * Begin a nestable scroll operation along the given axes.
+     *
+     * <p>A view starting a nested scroll promises to abide by the following contract:</p>
+     *
+     * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case
+     * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}.
+     * In the case of touch scrolling the nested scroll will be terminated automatically in
+     * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}.
+     * In the event of programmatic scrolling the caller must explicitly call
+     * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p>
+     *
+     * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found.
+     * If it returns false the caller may ignore the rest of this contract until the next scroll.
+     * Calling startNestedScroll while a nested scroll is already in progress will return true.</p>
+     *
+     * <p>At each incremental step of the scroll the caller should invoke
+     * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll}
+     * once it has calculated the requested scrolling delta. If it returns true the nested scrolling
+     * parent at least partially consumed the scroll and the caller should adjust the amount it
+     * scrolls by.</p>
+     *
+     * <p>After applying the remainder of the scroll delta the caller should invoke
+     * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing
+     * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat
+     * these values differently. See
+     * {@link NestedScrollingParent#onNestedScroll(View, int, int, int, int)}.
+     * </p>
+     *
+     * @param axes Flags consisting of a combination of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL}
+     *             and/or {@link ViewCompat#SCROLL_AXIS_VERTICAL}.
+     * @return true if a cooperative parent was found and nested scrolling has been enabled for
+     *         the current gesture.
+     *
+     * @see #stopNestedScroll()
+     * @see #dispatchNestedPreScroll(int, int, int[], int[])
+     * @see #dispatchNestedScroll(int, int, int, int, int[])
+     */
+    boolean startNestedScroll(int axes);
+
+    /**
+     * Stop a nested scroll in progress.
+     *
+     * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p>
+     *
+     * @see #startNestedScroll(int)
+     */
+    void stopNestedScroll();
+
+    /**
+     * Returns true if this view has a nested scrolling parent.
+     *
+     * <p>The presence of a nested scrolling parent indicates that this view has initiated
+     * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p>
+     *
+     * @return whether this view has a nested scrolling parent
+     */
+    boolean hasNestedScrollingParent();
+
+    /**
+     * Dispatch one step of a nested scroll in progress.
+     *
+     * <p>Implementations of views that support nested scrolling should call this to report
+     * info about a scroll in progress to the current nested scrolling parent. If a nested scroll
+     * is not currently in progress or nested scrolling is not
+     * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p>
+     *
+     * <p>Compatible View implementations should also call
+     * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before
+     * consuming a component of the scroll event themselves.</p>
+     *
+     * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step
+     * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step
+     * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view
+     * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view
+     * @param offsetInWindow Optional. If not null, on return this will contain the offset
+     *                       in local view coordinates of this view from before this operation
+     *                       to after it completes. View implementations may use this to adjust
+     *                       expected input coordinate tracking.
+     * @return true if the event was dispatched, false if it could not be dispatched.
+     * @see #dispatchNestedPreScroll(int, int, int[], int[])
+     */
+    boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);
+
+    /**
+     * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
+     *
+     * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch.
+     * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested
+     * scrolling operation to consume some or all of the scroll operation before the child view
+     * consumes it.</p>
+     *
+     * @param dx Horizontal scroll distance in pixels
+     * @param dy Vertical scroll distance in pixels
+     * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx
+     *                 and consumed[1] the consumed dy.
+     * @param offsetInWindow Optional. If not null, on return this will contain the offset
+     *                       in local view coordinates of this view from before this operation
+     *                       to after it completes. View implementations may use this to adjust
+     *                       expected input coordinate tracking.
+     * @return true if the parent consumed some or all of the scroll delta
+     * @see #dispatchNestedScroll(int, int, int, int, int[])
+     */
+    boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);
+
+    /**
+     * Dispatch a fling to a nested scrolling parent.
+     *
+     * <p>This method should be used to indicate that a nested scrolling child has detected
+     * suitable conditions for a fling. Generally this means that a touch scroll has ended with a
+     * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
+     * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
+     * along a scrollable axis.</p>
+     *
+     * <p>If a nested scrolling child view would normally fling but it is at the edge of
+     * its own content, it can use this method to delegate the fling to its nested scrolling
+     * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
+     *
+     * @param velocityX Horizontal fling velocity in pixels per second
+     * @param velocityY Vertical fling velocity in pixels per second
+     * @param consumed true if the child consumed the fling, false otherwise
+     * @return true if the nested scrolling parent consumed or otherwise reacted to the fling
+     */
+    boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed);
+
+    /**
+     * Dispatch a fling to a nested scrolling parent before it is processed by this view.
+     *
+     * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch
+     * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code>
+     * offsets an opportunity for the parent view in a nested fling to fully consume the fling
+     * before the child view consumes it. If this method returns <code>true</code>, a nested
+     * parent view consumed the fling and this view should not scroll as a result.</p>
+     *
+     * <p>For a better user experience, only one view in a nested scrolling chain should consume
+     * the fling at a time. If a parent view consumed the fling this method will return false.
+     * Custom view implementations should account for this in two ways:</p>
+     *
+     * <ul>
+     *     <li>If a custom view is paged and needs to settle to a fixed page-point, do not
+     *     call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid
+     *     position regardless.</li>
+     *     <li>If a nested parent does consume the fling, this view should not scroll at all,
+     *     even to settle back to a valid idle position.</li>
+     * </ul>
+     *
+     * <p>Views should also not offer fling velocities to nested parent views along an axis
+     * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView}
+     * should not offer a horizontal fling velocity to its parents since scrolling along that
+     * axis is not permitted and carrying velocity along that motion does not make sense.</p>
+     *
+     * @param velocityX Horizontal fling velocity in pixels per second
+     * @param velocityY Vertical fling velocity in pixels per second
+     * @return true if a nested scrolling parent consumed the fling
+     */
+    boolean dispatchNestedPreFling(float velocityX, float velocityY);
+}
diff --git a/core/java/com/android/internal/widget/OpReorderer.java b/core/java/com/android/internal/widget/OpReorderer.java
new file mode 100644
index 0000000..babb087
--- /dev/null
+++ b/core/java/com/android/internal/widget/OpReorderer.java
@@ -0,0 +1,239 @@
+/*
+ * 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.widget;
+
+import static com.android.internal.widget.AdapterHelper.UpdateOp.ADD;
+import static com.android.internal.widget.AdapterHelper.UpdateOp.MOVE;
+import static com.android.internal.widget.AdapterHelper.UpdateOp.REMOVE;
+import static com.android.internal.widget.AdapterHelper.UpdateOp.UPDATE;
+
+import com.android.internal.widget.AdapterHelper.UpdateOp;
+
+import java.util.List;
+
+class OpReorderer {
+
+    final Callback mCallback;
+
+    OpReorderer(Callback callback) {
+        mCallback = callback;
+    }
+
+    void reorderOps(List<UpdateOp> ops) {
+        // since move operations breaks continuity, their effects on ADD/RM are hard to handle.
+        // we push them to the end of the list so that they can be handled easily.
+        int badMove;
+        while ((badMove = getLastMoveOutOfOrder(ops)) != -1) {
+            swapMoveOp(ops, badMove, badMove + 1);
+        }
+    }
+
+    private void swapMoveOp(List<UpdateOp> list, int badMove, int next) {
+        final UpdateOp moveOp = list.get(badMove);
+        final UpdateOp nextOp = list.get(next);
+        switch (nextOp.cmd) {
+            case REMOVE:
+                swapMoveRemove(list, badMove, moveOp, next, nextOp);
+                break;
+            case ADD:
+                swapMoveAdd(list, badMove, moveOp, next, nextOp);
+                break;
+            case UPDATE:
+                swapMoveUpdate(list, badMove, moveOp, next, nextOp);
+                break;
+        }
+    }
+
+    void swapMoveRemove(List<UpdateOp> list, int movePos, UpdateOp moveOp,
+            int removePos, UpdateOp removeOp) {
+        UpdateOp extraRm = null;
+        // check if move is nulled out by remove
+        boolean revertedMove = false;
+        final boolean moveIsBackwards;
+
+        if (moveOp.positionStart < moveOp.itemCount) {
+            moveIsBackwards = false;
+            if (removeOp.positionStart == moveOp.positionStart
+                    && removeOp.itemCount == moveOp.itemCount - moveOp.positionStart) {
+                revertedMove = true;
+            }
+        } else {
+            moveIsBackwards = true;
+            if (removeOp.positionStart == moveOp.itemCount + 1
+                    && removeOp.itemCount == moveOp.positionStart - moveOp.itemCount) {
+                revertedMove = true;
+            }
+        }
+
+        // going in reverse, first revert the effect of add
+        if (moveOp.itemCount < removeOp.positionStart) {
+            removeOp.positionStart--;
+        } else if (moveOp.itemCount < removeOp.positionStart + removeOp.itemCount) {
+            // move is removed.
+            removeOp.itemCount--;
+            moveOp.cmd = REMOVE;
+            moveOp.itemCount = 1;
+            if (removeOp.itemCount == 0) {
+                list.remove(removePos);
+                mCallback.recycleUpdateOp(removeOp);
+            }
+            // no need to swap, it is already a remove
+            return;
+        }
+
+        // now affect of add is consumed. now apply effect of first remove
+        if (moveOp.positionStart <= removeOp.positionStart) {
+            removeOp.positionStart++;
+        } else if (moveOp.positionStart < removeOp.positionStart + removeOp.itemCount) {
+            final int remaining = removeOp.positionStart + removeOp.itemCount
+                    - moveOp.positionStart;
+            extraRm = mCallback.obtainUpdateOp(REMOVE, moveOp.positionStart + 1, remaining, null);
+            removeOp.itemCount = moveOp.positionStart - removeOp.positionStart;
+        }
+
+        // if effects of move is reverted by remove, we are done.
+        if (revertedMove) {
+            list.set(movePos, removeOp);
+            list.remove(removePos);
+            mCallback.recycleUpdateOp(moveOp);
+            return;
+        }
+
+        // now find out the new locations for move actions
+        if (moveIsBackwards) {
+            if (extraRm != null) {
+                if (moveOp.positionStart > extraRm.positionStart) {
+                    moveOp.positionStart -= extraRm.itemCount;
+                }
+                if (moveOp.itemCount > extraRm.positionStart) {
+                    moveOp.itemCount -= extraRm.itemCount;
+                }
+            }
+            if (moveOp.positionStart > removeOp.positionStart) {
+                moveOp.positionStart -= removeOp.itemCount;
+            }
+            if (moveOp.itemCount > removeOp.positionStart) {
+                moveOp.itemCount -= removeOp.itemCount;
+            }
+        } else {
+            if (extraRm != null) {
+                if (moveOp.positionStart >= extraRm.positionStart) {
+                    moveOp.positionStart -= extraRm.itemCount;
+                }
+                if (moveOp.itemCount >= extraRm.positionStart) {
+                    moveOp.itemCount -= extraRm.itemCount;
+                }
+            }
+            if (moveOp.positionStart >= removeOp.positionStart) {
+                moveOp.positionStart -= removeOp.itemCount;
+            }
+            if (moveOp.itemCount >= removeOp.positionStart) {
+                moveOp.itemCount -= removeOp.itemCount;
+            }
+        }
+
+        list.set(movePos, removeOp);
+        if (moveOp.positionStart != moveOp.itemCount) {
+            list.set(removePos, moveOp);
+        } else {
+            list.remove(removePos);
+        }
+        if (extraRm != null) {
+            list.add(movePos, extraRm);
+        }
+    }
+
+    private void swapMoveAdd(List<UpdateOp> list, int move, UpdateOp moveOp, int add,
+            UpdateOp addOp) {
+        int offset = 0;
+        // going in reverse, first revert the effect of add
+        if (moveOp.itemCount < addOp.positionStart) {
+            offset--;
+        }
+        if (moveOp.positionStart < addOp.positionStart) {
+            offset++;
+        }
+        if (addOp.positionStart <= moveOp.positionStart) {
+            moveOp.positionStart += addOp.itemCount;
+        }
+        if (addOp.positionStart <= moveOp.itemCount) {
+            moveOp.itemCount += addOp.itemCount;
+        }
+        addOp.positionStart += offset;
+        list.set(move, addOp);
+        list.set(add, moveOp);
+    }
+
+    void swapMoveUpdate(List<UpdateOp> list, int move, UpdateOp moveOp, int update,
+            UpdateOp updateOp) {
+        UpdateOp extraUp1 = null;
+        UpdateOp extraUp2 = null;
+        // going in reverse, first revert the effect of add
+        if (moveOp.itemCount < updateOp.positionStart) {
+            updateOp.positionStart--;
+        } else if (moveOp.itemCount < updateOp.positionStart + updateOp.itemCount) {
+            // moved item is updated. add an update for it
+            updateOp.itemCount--;
+            extraUp1 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart, 1, updateOp.payload);
+        }
+        // now affect of add is consumed. now apply effect of first remove
+        if (moveOp.positionStart <= updateOp.positionStart) {
+            updateOp.positionStart++;
+        } else if (moveOp.positionStart < updateOp.positionStart + updateOp.itemCount) {
+            final int remaining = updateOp.positionStart + updateOp.itemCount
+                    - moveOp.positionStart;
+            extraUp2 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart + 1, remaining,
+                    updateOp.payload);
+            updateOp.itemCount -= remaining;
+        }
+        list.set(update, moveOp);
+        if (updateOp.itemCount > 0) {
+            list.set(move, updateOp);
+        } else {
+            list.remove(move);
+            mCallback.recycleUpdateOp(updateOp);
+        }
+        if (extraUp1 != null) {
+            list.add(move, extraUp1);
+        }
+        if (extraUp2 != null) {
+            list.add(move, extraUp2);
+        }
+    }
+
+    private int getLastMoveOutOfOrder(List<UpdateOp> list) {
+        boolean foundNonMove = false;
+        for (int i = list.size() - 1; i >= 0; i--) {
+            final UpdateOp op1 = list.get(i);
+            if (op1.cmd == MOVE) {
+                if (foundNonMove) {
+                    return i;
+                }
+            } else {
+                foundNonMove = true;
+            }
+        }
+        return -1;
+    }
+
+    interface Callback {
+
+        UpdateOp obtainUpdateOp(int cmd, int startPosition, int itemCount, Object payload);
+
+        void recycleUpdateOp(UpdateOp op);
+    }
+}
diff --git a/core/java/com/android/internal/widget/OrientationHelper.java b/core/java/com/android/internal/widget/OrientationHelper.java
new file mode 100644
index 0000000..1b02c88
--- /dev/null
+++ b/core/java/com/android/internal/widget/OrientationHelper.java
@@ -0,0 +1,439 @@
+/*
+ * 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.widget;
+
+import android.graphics.Rect;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
+ * <p>
+ * It is developed to easily support vertical and horizontal orientations in a LayoutManager but
+ * can also be used to abstract calls around view bounds and child measurements with margins and
+ * decorations.
+ *
+ * @see #createHorizontalHelper(RecyclerView.LayoutManager)
+ * @see #createVerticalHelper(RecyclerView.LayoutManager)
+ */
+public abstract class OrientationHelper {
+
+    private static final int INVALID_SIZE = Integer.MIN_VALUE;
+
+    protected final RecyclerView.LayoutManager mLayoutManager;
+
+    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
+
+    public static final int VERTICAL = LinearLayout.VERTICAL;
+
+    private int mLastTotalSpace = INVALID_SIZE;
+
+    final Rect mTmpRect = new Rect();
+
+    private OrientationHelper(RecyclerView.LayoutManager layoutManager) {
+        mLayoutManager = layoutManager;
+    }
+
+    /**
+     * Call this method after onLayout method is complete if state is NOT pre-layout.
+     * This method records information like layout bounds that might be useful in the next layout
+     * calculations.
+     */
+    public void onLayoutComplete() {
+        mLastTotalSpace = getTotalSpace();
+    }
+
+    /**
+     * Returns the layout space change between the previous layout pass and current layout pass.
+     * <p>
+     * Make sure you call {@link #onLayoutComplete()} at the end of your LayoutManager's
+     * {@link RecyclerView.LayoutManager#onLayoutChildren(RecyclerView.Recycler,
+     * RecyclerView.State)} method.
+     *
+     * @return The difference between the current total space and previous layout's total space.
+     * @see #onLayoutComplete()
+     */
+    public int getTotalSpaceChange() {
+        return INVALID_SIZE == mLastTotalSpace ? 0 : getTotalSpace() - mLastTotalSpace;
+    }
+
+    /**
+     * Returns the start of the view including its decoration and margin.
+     * <p>
+     * For example, for the horizontal helper, if a View's left is at pixel 20, has 2px left
+     * decoration and 3px left margin, returned value will be 15px.
+     *
+     * @param view The view element to check
+     * @return The first pixel of the element
+     * @see #getDecoratedEnd(android.view.View)
+     */
+    public abstract int getDecoratedStart(View view);
+
+    /**
+     * Returns the end of the view including its decoration and margin.
+     * <p>
+     * For example, for the horizontal helper, if a View's right is at pixel 200, has 2px right
+     * decoration and 3px right margin, returned value will be 205.
+     *
+     * @param view The view element to check
+     * @return The last pixel of the element
+     * @see #getDecoratedStart(android.view.View)
+     */
+    public abstract int getDecoratedEnd(View view);
+
+    /**
+     * Returns the end of the View after its matrix transformations are applied to its layout
+     * position.
+     * <p>
+     * This method is useful when trying to detect the visible edge of a View.
+     * <p>
+     * It includes the decorations but does not include the margins.
+     *
+     * @param view The view whose transformed end will be returned
+     * @return The end of the View after its decor insets and transformation matrix is applied to
+     * its position
+     *
+     * @see RecyclerView.LayoutManager#getTransformedBoundingBox(View, boolean, Rect)
+     */
+    public abstract int getTransformedEndWithDecoration(View view);
+
+    /**
+     * Returns the start of the View after its matrix transformations are applied to its layout
+     * position.
+     * <p>
+     * This method is useful when trying to detect the visible edge of a View.
+     * <p>
+     * It includes the decorations but does not include the margins.
+     *
+     * @param view The view whose transformed start will be returned
+     * @return The start of the View after its decor insets and transformation matrix is applied to
+     * its position
+     *
+     * @see RecyclerView.LayoutManager#getTransformedBoundingBox(View, boolean, Rect)
+     */
+    public abstract int getTransformedStartWithDecoration(View view);
+
+    /**
+     * Returns the space occupied by this View in the current orientation including decorations and
+     * margins.
+     *
+     * @param view The view element to check
+     * @return Total space occupied by this view
+     * @see #getDecoratedMeasurementInOther(View)
+     */
+    public abstract int getDecoratedMeasurement(View view);
+
+    /**
+     * Returns the space occupied by this View in the perpendicular orientation including
+     * decorations and margins.
+     *
+     * @param view The view element to check
+     * @return Total space occupied by this view in the perpendicular orientation to current one
+     * @see #getDecoratedMeasurement(View)
+     */
+    public abstract int getDecoratedMeasurementInOther(View view);
+
+    /**
+     * Returns the start position of the layout after the start padding is added.
+     *
+     * @return The very first pixel we can draw.
+     */
+    public abstract int getStartAfterPadding();
+
+    /**
+     * Returns the end position of the layout after the end padding is removed.
+     *
+     * @return The end boundary for this layout.
+     */
+    public abstract int getEndAfterPadding();
+
+    /**
+     * Returns the end position of the layout without taking padding into account.
+     *
+     * @return The end boundary for this layout without considering padding.
+     */
+    public abstract int getEnd();
+
+    /**
+     * Offsets all children's positions by the given amount.
+     *
+     * @param amount Value to add to each child's layout parameters
+     */
+    public abstract void offsetChildren(int amount);
+
+    /**
+     * Returns the total space to layout. This number is the difference between
+     * {@link #getEndAfterPadding()} and {@link #getStartAfterPadding()}.
+     *
+     * @return Total space to layout children
+     */
+    public abstract int getTotalSpace();
+
+    /**
+     * Offsets the child in this orientation.
+     *
+     * @param view   View to offset
+     * @param offset offset amount
+     */
+    public abstract void offsetChild(View view, int offset);
+
+    /**
+     * Returns the padding at the end of the layout. For horizontal helper, this is the right
+     * padding and for vertical helper, this is the bottom padding. This method does not check
+     * whether the layout is RTL or not.
+     *
+     * @return The padding at the end of the layout.
+     */
+    public abstract int getEndPadding();
+
+    /**
+     * Returns the MeasureSpec mode for the current orientation from the LayoutManager.
+     *
+     * @return The current measure spec mode.
+     *
+     * @see View.MeasureSpec
+     * @see RecyclerView.LayoutManager#getWidthMode()
+     * @see RecyclerView.LayoutManager#getHeightMode()
+     */
+    public abstract int getMode();
+
+    /**
+     * Returns the MeasureSpec mode for the perpendicular orientation from the LayoutManager.
+     *
+     * @return The current measure spec mode.
+     *
+     * @see View.MeasureSpec
+     * @see RecyclerView.LayoutManager#getWidthMode()
+     * @see RecyclerView.LayoutManager#getHeightMode()
+     */
+    public abstract int getModeInOther();
+
+    /**
+     * Creates an OrientationHelper for the given LayoutManager and orientation.
+     *
+     * @param layoutManager LayoutManager to attach to
+     * @param orientation   Desired orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}
+     * @return A new OrientationHelper
+     */
+    public static OrientationHelper createOrientationHelper(
+            RecyclerView.LayoutManager layoutManager, int orientation) {
+        switch (orientation) {
+            case HORIZONTAL:
+                return createHorizontalHelper(layoutManager);
+            case VERTICAL:
+                return createVerticalHelper(layoutManager);
+        }
+        throw new IllegalArgumentException("invalid orientation");
+    }
+
+    /**
+     * Creates a horizontal OrientationHelper for the given LayoutManager.
+     *
+     * @param layoutManager The LayoutManager to attach to.
+     * @return A new OrientationHelper
+     */
+    public static OrientationHelper createHorizontalHelper(
+            RecyclerView.LayoutManager layoutManager) {
+        return new OrientationHelper(layoutManager) {
+            @Override
+            public int getEndAfterPadding() {
+                return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight();
+            }
+
+            @Override
+            public int getEnd() {
+                return mLayoutManager.getWidth();
+            }
+
+            @Override
+            public void offsetChildren(int amount) {
+                mLayoutManager.offsetChildrenHorizontal(amount);
+            }
+
+            @Override
+            public int getStartAfterPadding() {
+                return mLayoutManager.getPaddingLeft();
+            }
+
+            @Override
+            public int getDecoratedMeasurement(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
+                        + params.rightMargin;
+            }
+
+            @Override
+            public int getDecoratedMeasurementInOther(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
+                        + params.bottomMargin;
+            }
+
+            @Override
+            public int getDecoratedEnd(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedRight(view) + params.rightMargin;
+            }
+
+            @Override
+            public int getDecoratedStart(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedLeft(view) - params.leftMargin;
+            }
+
+            @Override
+            public int getTransformedEndWithDecoration(View view) {
+                mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
+                return mTmpRect.right;
+            }
+
+            @Override
+            public int getTransformedStartWithDecoration(View view) {
+                mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
+                return mTmpRect.left;
+            }
+
+            @Override
+            public int getTotalSpace() {
+                return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft()
+                        - mLayoutManager.getPaddingRight();
+            }
+
+            @Override
+            public void offsetChild(View view, int offset) {
+                view.offsetLeftAndRight(offset);
+            }
+
+            @Override
+            public int getEndPadding() {
+                return mLayoutManager.getPaddingRight();
+            }
+
+            @Override
+            public int getMode() {
+                return mLayoutManager.getWidthMode();
+            }
+
+            @Override
+            public int getModeInOther() {
+                return mLayoutManager.getHeightMode();
+            }
+        };
+    }
+
+    /**
+     * Creates a vertical OrientationHelper for the given LayoutManager.
+     *
+     * @param layoutManager The LayoutManager to attach to.
+     * @return A new OrientationHelper
+     */
+    public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) {
+        return new OrientationHelper(layoutManager) {
+            @Override
+            public int getEndAfterPadding() {
+                return mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom();
+            }
+
+            @Override
+            public int getEnd() {
+                return mLayoutManager.getHeight();
+            }
+
+            @Override
+            public void offsetChildren(int amount) {
+                mLayoutManager.offsetChildrenVertical(amount);
+            }
+
+            @Override
+            public int getStartAfterPadding() {
+                return mLayoutManager.getPaddingTop();
+            }
+
+            @Override
+            public int getDecoratedMeasurement(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
+                        + params.bottomMargin;
+            }
+
+            @Override
+            public int getDecoratedMeasurementInOther(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
+                        + params.rightMargin;
+            }
+
+            @Override
+            public int getDecoratedEnd(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedBottom(view) + params.bottomMargin;
+            }
+
+            @Override
+            public int getDecoratedStart(View view) {
+                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
+                        view.getLayoutParams();
+                return mLayoutManager.getDecoratedTop(view) - params.topMargin;
+            }
+
+            @Override
+            public int getTransformedEndWithDecoration(View view) {
+                mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
+                return mTmpRect.bottom;
+            }
+
+            @Override
+            public int getTransformedStartWithDecoration(View view) {
+                mLayoutManager.getTransformedBoundingBox(view, true, mTmpRect);
+                return mTmpRect.top;
+            }
+
+            @Override
+            public int getTotalSpace() {
+                return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop()
+                        - mLayoutManager.getPaddingBottom();
+            }
+
+            @Override
+            public void offsetChild(View view, int offset) {
+                view.offsetTopAndBottom(offset);
+            }
+
+            @Override
+            public int getEndPadding() {
+                return mLayoutManager.getPaddingBottom();
+            }
+
+            @Override
+            public int getMode() {
+                return mLayoutManager.getHeightMode();
+            }
+
+            @Override
+            public int getModeInOther() {
+                return mLayoutManager.getWidthMode();
+            }
+        };
+    }
+}
diff --git a/core/java/com/android/internal/widget/RecyclerView.java b/core/java/com/android/internal/widget/RecyclerView.java
new file mode 100644
index 0000000..0cf3164
--- /dev/null
+++ b/core/java/com/android/internal/widget/RecyclerView.java
@@ -0,0 +1,12255 @@
+/*
+ * 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.widget;
+
+import android.annotation.CallSuper;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.database.Observable;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.TypedValue;
+import android.view.AbsSavedState;
+import android.view.Display;
+import android.view.FocusFinder;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.Interpolator;
+import android.widget.EdgeEffect;
+import android.widget.OverScroller;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A flexible view for providing a limited window into a large data set.
+ *
+ * <h3>Glossary of terms:</h3>
+ *
+ * <ul>
+ *     <li><em>Adapter:</em> A subclass of {@link Adapter} responsible for providing views
+ *     that represent items in a data set.</li>
+ *     <li><em>Position:</em> The position of a data item within an <em>Adapter</em>.</li>
+ *     <li><em>Index:</em> The index of an attached child view as used in a call to
+ *     {@link ViewGroup#getChildAt}. Contrast with <em>Position.</em></li>
+ *     <li><em>Binding:</em> The process of preparing a child view to display data corresponding
+ *     to a <em>position</em> within the adapter.</li>
+ *     <li><em>Recycle (view):</em> A view previously used to display data for a specific adapter
+ *     position may be placed in a cache for later reuse to display the same type of data again
+ *     later. This can drastically improve performance by skipping initial layout inflation
+ *     or construction.</li>
+ *     <li><em>Scrap (view):</em> A child view that has entered into a temporarily detached
+ *     state during layout. Scrap views may be reused without becoming fully detached
+ *     from the parent RecyclerView, either unmodified if no rebinding is required or modified
+ *     by the adapter if the view was considered <em>dirty</em>.</li>
+ *     <li><em>Dirty (view):</em> A child view that must be rebound by the adapter before
+ *     being displayed.</li>
+ * </ul>
+ *
+ * <h4>Positions in RecyclerView:</h4>
+ * <p>
+ * RecyclerView introduces an additional level of abstraction between the {@link Adapter} and
+ * {@link LayoutManager} to be able to detect data set changes in batches during a layout
+ * calculation. This saves LayoutManager from tracking adapter changes to calculate animations.
+ * It also helps with performance because all view bindings happen at the same time and unnecessary
+ * bindings are avoided.
+ * <p>
+ * For this reason, there are two types of <code>position</code> related methods in RecyclerView:
+ * <ul>
+ *     <li>layout position: Position of an item in the latest layout calculation. This is the
+ *     position from the LayoutManager's perspective.</li>
+ *     <li>adapter position: Position of an item in the adapter. This is the position from
+ *     the Adapter's perspective.</li>
+ * </ul>
+ * <p>
+ * These two positions are the same except the time between dispatching <code>adapter.notify*
+ * </code> events and calculating the updated layout.
+ * <p>
+ * Methods that return or receive <code>*LayoutPosition*</code> use position as of the latest
+ * layout calculation (e.g. {@link ViewHolder#getLayoutPosition()},
+ * {@link #findViewHolderForLayoutPosition(int)}). These positions include all changes until the
+ * last layout calculation. You can rely on these positions to be consistent with what user is
+ * currently seeing on the screen. For example, if you have a list of items on the screen and user
+ * asks for the 5<sup>th</sup> element, you should use these methods as they'll match what user
+ * is seeing.
+ * <p>
+ * The other set of position related methods are in the form of
+ * <code>*AdapterPosition*</code>. (e.g. {@link ViewHolder#getAdapterPosition()},
+ * {@link #findViewHolderForAdapterPosition(int)}) You should use these methods when you need to
+ * work with up-to-date adapter positions even if they may not have been reflected to layout yet.
+ * For example, if you want to access the item in the adapter on a ViewHolder click, you should use
+ * {@link ViewHolder#getAdapterPosition()}. Beware that these methods may not be able to calculate
+ * adapter positions if {@link Adapter#notifyDataSetChanged()} has been called and new layout has
+ * not yet been calculated. For this reasons, you should carefully handle {@link #NO_POSITION} or
+ * <code>null</code> results from these methods.
+ * <p>
+ * When writing a {@link LayoutManager} you almost always want to use layout positions whereas when
+ * writing an {@link Adapter}, you probably want to use adapter positions.
+ *
+ * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_layoutManager
+ */
+public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {
+
+    static final String TAG = "RecyclerView";
+
+    static final boolean DEBUG = false;
+
+    private static final int[]  NESTED_SCROLLING_ATTRS = { android.R.attr.nestedScrollingEnabled };
+
+    private static final int[] CLIP_TO_PADDING_ATTR = {android.R.attr.clipToPadding};
+
+    /**
+     * On Kitkat and JB MR2, there is a bug which prevents DisplayList from being invalidated if
+     * a View is two levels deep(wrt to ViewHolder.itemView). DisplayList can be invalidated by
+     * setting View's visibility to INVISIBLE when View is detached. On Kitkat and JB MR2, Recycler
+     * recursively traverses itemView and invalidates display list for each ViewGroup that matches
+     * this criteria.
+     */
+    static final boolean FORCE_INVALIDATE_DISPLAY_LIST = Build.VERSION.SDK_INT == 18
+            || Build.VERSION.SDK_INT == 19 || Build.VERSION.SDK_INT == 20;
+    /**
+     * On M+, an unspecified measure spec may include a hint which we can use. On older platforms,
+     * this value might be garbage. To save LayoutManagers from it, RecyclerView sets the size to
+     * 0 when mode is unspecified.
+     */
+    static final boolean ALLOW_SIZE_IN_UNSPECIFIED_SPEC = Build.VERSION.SDK_INT >= 23;
+
+    static final boolean POST_UPDATES_ON_ANIMATION = Build.VERSION.SDK_INT >= 16;
+
+    /**
+     * On L+, with RenderThread, the UI thread has idle time after it has passed a frame off to
+     * RenderThread but before the next frame begins. We schedule prefetch work in this window.
+     */
+    private static final boolean ALLOW_THREAD_GAP_WORK = Build.VERSION.SDK_INT >= 21;
+
+    /**
+     * FocusFinder#findNextFocus is broken on ICS MR1 and older for View.FOCUS_BACKWARD direction.
+     * We convert it to an absolute direction such as FOCUS_DOWN or FOCUS_LEFT.
+     */
+    private static final boolean FORCE_ABS_FOCUS_SEARCH_DIRECTION = Build.VERSION.SDK_INT <= 15;
+
+    /**
+     * on API 15-, a focused child can still be considered a focused child of RV even after
+     * it's being removed or its focusable flag is set to false. This is because when this focused
+     * child is detached, the reference to this child is not removed in clearFocus. API 16 and above
+     * properly handle this case by calling ensureInputFocusOnFirstFocusable or rootViewRequestFocus
+     * to request focus on a new child, which will clear the focus on the old (detached) child as a
+     * side-effect.
+     */
+    private static final boolean IGNORE_DETACHED_FOCUSED_CHILD = Build.VERSION.SDK_INT <= 15;
+
+    static final boolean DISPATCH_TEMP_DETACH = false;
+    public static final int HORIZONTAL = 0;
+    public static final int VERTICAL = 1;
+
+    public static final int NO_POSITION = -1;
+    public static final long NO_ID = -1;
+    public static final int INVALID_TYPE = -1;
+
+    /**
+     * Constant for use with {@link #setScrollingTouchSlop(int)}. Indicates
+     * that the RecyclerView should use the standard touch slop for smooth,
+     * continuous scrolling.
+     */
+    public static final int TOUCH_SLOP_DEFAULT = 0;
+
+    /**
+     * Constant for use with {@link #setScrollingTouchSlop(int)}. Indicates
+     * that the RecyclerView should use the standard touch slop for scrolling
+     * widgets that snap to a page or other coarse-grained barrier.
+     */
+    public static final int TOUCH_SLOP_PAGING = 1;
+
+    static final int MAX_SCROLL_DURATION = 2000;
+
+    /**
+     * RecyclerView is calculating a scroll.
+     * If there are too many of these in Systrace, some Views inside RecyclerView might be causing
+     * it. Try to avoid using EditText, focusable views or handle them with care.
+     */
+    static final String TRACE_SCROLL_TAG = "RV Scroll";
+
+    /**
+     * OnLayout has been called by the View system.
+     * If this shows up too many times in Systrace, make sure the children of RecyclerView do not
+     * update themselves directly. This will cause a full re-layout but when it happens via the
+     * Adapter notifyItemChanged, RecyclerView can avoid full layout calculation.
+     */
+    private static final String TRACE_ON_LAYOUT_TAG = "RV OnLayout";
+
+    /**
+     * NotifyDataSetChanged or equal has been called.
+     * If this is taking a long time, try sending granular notify adapter changes instead of just
+     * calling notifyDataSetChanged or setAdapter / swapAdapter. Adding stable ids to your adapter
+     * might help.
+     */
+    private static final String TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG = "RV FullInvalidate";
+
+    /**
+     * RecyclerView is doing a layout for partial adapter updates (we know what has changed)
+     * If this is taking a long time, you may have dispatched too many Adapter updates causing too
+     * many Views being rebind. Make sure all are necessary and also prefer using notify*Range
+     * methods.
+     */
+    private static final String TRACE_HANDLE_ADAPTER_UPDATES_TAG = "RV PartialInvalidate";
+
+    /**
+     * RecyclerView is rebinding a View.
+     * If this is taking a lot of time, consider optimizing your layout or make sure you are not
+     * doing extra operations in onBindViewHolder call.
+     */
+    static final String TRACE_BIND_VIEW_TAG = "RV OnBindView";
+
+    /**
+     * RecyclerView is attempting to pre-populate off screen views.
+     */
+    static final String TRACE_PREFETCH_TAG = "RV Prefetch";
+
+    /**
+     * RecyclerView is attempting to pre-populate off screen itemviews within an off screen
+     * RecyclerView.
+     */
+    static final String TRACE_NESTED_PREFETCH_TAG = "RV Nested Prefetch";
+
+    /**
+     * RecyclerView is creating a new View.
+     * If too many of these present in Systrace:
+     * - There might be a problem in Recycling (e.g. custom Animations that set transient state and
+     * prevent recycling or ItemAnimator not implementing the contract properly. ({@link
+     * > Adapter#onFailedToRecycleView(ViewHolder)})
+     *
+     * - There might be too many item view types.
+     * > Try merging them
+     *
+     * - There might be too many itemChange animations and not enough space in RecyclerPool.
+     * >Try increasing your pool size and item cache size.
+     */
+    static final String TRACE_CREATE_VIEW_TAG = "RV CreateView";
+    private static final Class<?>[] LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE =
+            new Class[]{Context.class, AttributeSet.class, int.class, int.class};
+
+    private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
+
+    final Recycler mRecycler = new Recycler();
+
+    private SavedState mPendingSavedState;
+
+    /**
+     * Handles adapter updates
+     */
+    AdapterHelper mAdapterHelper;
+
+    /**
+     * Handles abstraction between LayoutManager children and RecyclerView children
+     */
+    ChildHelper mChildHelper;
+
+    /**
+     * Keeps data about views to be used for animations
+     */
+    final ViewInfoStore mViewInfoStore = new ViewInfoStore();
+
+    /**
+     * Prior to L, there is no way to query this variable which is why we override the setter and
+     * track it here.
+     */
+    boolean mClipToPadding;
+
+    /**
+     * Note: this Runnable is only ever posted if:
+     * 1) We've been through first layout
+     * 2) We know we have a fixed size (mHasFixedSize)
+     * 3) We're attached
+     */
+    final Runnable mUpdateChildViewsRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (!mFirstLayoutComplete || isLayoutRequested()) {
+                // a layout request will happen, we should not do layout here.
+                return;
+            }
+            if (!mIsAttached) {
+                requestLayout();
+                // if we are not attached yet, mark us as requiring layout and skip
+                return;
+            }
+            if (mLayoutFrozen) {
+                mLayoutRequestEaten = true;
+                return; //we'll process updates when ice age ends.
+            }
+            consumePendingUpdateOperations();
+        }
+    };
+
+    final Rect mTempRect = new Rect();
+    private final Rect mTempRect2 = new Rect();
+    final RectF mTempRectF = new RectF();
+    Adapter mAdapter;
+    @VisibleForTesting LayoutManager mLayout;
+    RecyclerListener mRecyclerListener;
+    final ArrayList<ItemDecoration> mItemDecorations = new ArrayList<>();
+    private final ArrayList<OnItemTouchListener> mOnItemTouchListeners =
+            new ArrayList<>();
+    private OnItemTouchListener mActiveOnItemTouchListener;
+    boolean mIsAttached;
+    boolean mHasFixedSize;
+    @VisibleForTesting boolean mFirstLayoutComplete;
+
+    // Counting lock to control whether we should ignore requestLayout calls from children or not.
+    private int mEatRequestLayout = 0;
+
+    boolean mLayoutRequestEaten;
+    boolean mLayoutFrozen;
+    private boolean mIgnoreMotionEventTillDown;
+
+    // binary OR of change events that were eaten during a layout or scroll.
+    private int mEatenAccessibilityChangeFlags;
+    boolean mAdapterUpdateDuringMeasure;
+
+    private final AccessibilityManager mAccessibilityManager;
+    private List<OnChildAttachStateChangeListener> mOnChildAttachStateListeners;
+
+    /**
+     * Set to true when an adapter data set changed notification is received.
+     * In that case, we cannot run any animations since we don't know what happened until layout.
+     *
+     * Attached items are invalid until next layout, at which point layout will animate/replace
+     * items as necessary, building up content from the (effectively) new adapter from scratch.
+     *
+     * Cached items must be discarded when setting this to true, so that the cache may be freely
+     * used by prefetching until the next layout occurs.
+     *
+     * @see #setDataSetChangedAfterLayout()
+     */
+    boolean mDataSetHasChangedAfterLayout = false;
+
+    /**
+     * This variable is incremented during a dispatchLayout and/or scroll.
+     * Some methods should not be called during these periods (e.g. adapter data change).
+     * Doing so will create hard to find bugs so we better check it and throw an exception.
+     *
+     * @see #assertInLayoutOrScroll(String)
+     * @see #assertNotInLayoutOrScroll(String)
+     */
+    private int mLayoutOrScrollCounter = 0;
+
+    /**
+     * Similar to mLayoutOrScrollCounter but logs a warning instead of throwing an exception
+     * (for API compatibility).
+     * <p>
+     * It is a bad practice for a developer to update the data in a scroll callback since it is
+     * potentially called during a layout.
+     */
+    private int mDispatchScrollCounter = 0;
+
+    private EdgeEffect mLeftGlow, mTopGlow, mRightGlow, mBottomGlow;
+
+    ItemAnimator mItemAnimator = new DefaultItemAnimator();
+
+    private static final int INVALID_POINTER = -1;
+
+    /**
+     * The RecyclerView is not currently scrolling.
+     * @see #getScrollState()
+     */
+    public static final int SCROLL_STATE_IDLE = 0;
+
+    /**
+     * The RecyclerView is currently being dragged by outside input such as user touch input.
+     * @see #getScrollState()
+     */
+    public static final int SCROLL_STATE_DRAGGING = 1;
+
+    /**
+     * The RecyclerView is currently animating to a final position while not under
+     * outside control.
+     * @see #getScrollState()
+     */
+    public static final int SCROLL_STATE_SETTLING = 2;
+
+    static final long FOREVER_NS = Long.MAX_VALUE;
+
+    // Touch/scrolling handling
+
+    private int mScrollState = SCROLL_STATE_IDLE;
+    private int mScrollPointerId = INVALID_POINTER;
+    private VelocityTracker mVelocityTracker;
+    private int mInitialTouchX;
+    private int mInitialTouchY;
+    private int mLastTouchX;
+    private int mLastTouchY;
+    private int mTouchSlop;
+    private OnFlingListener mOnFlingListener;
+    private final int mMinFlingVelocity;
+    private final int mMaxFlingVelocity;
+    // This value is used when handling generic motion events.
+    private float mScrollFactor = Float.MIN_VALUE;
+    private boolean mPreserveFocusAfterLayout = true;
+
+    final ViewFlinger mViewFlinger = new ViewFlinger();
+
+    GapWorker mGapWorker;
+    GapWorker.LayoutPrefetchRegistryImpl mPrefetchRegistry =
+            ALLOW_THREAD_GAP_WORK ? new GapWorker.LayoutPrefetchRegistryImpl() : null;
+
+    final State mState = new State();
+
+    private OnScrollListener mScrollListener;
+    private List<OnScrollListener> mScrollListeners;
+
+    // For use in item animations
+    boolean mItemsAddedOrRemoved = false;
+    boolean mItemsChanged = false;
+    private ItemAnimator.ItemAnimatorListener mItemAnimatorListener =
+            new ItemAnimatorRestoreListener();
+    boolean mPostedAnimatorRunner = false;
+    RecyclerViewAccessibilityDelegate mAccessibilityDelegate;
+    private ChildDrawingOrderCallback mChildDrawingOrderCallback;
+
+    // simple array to keep min and max child position during a layout calculation
+    // preserved not to create a new one in each layout pass
+    private final int[] mMinMaxLayoutPositions = new int[2];
+
+    private final int[] mScrollOffset = new int[2];
+    private final int[] mScrollConsumed = new int[2];
+    private final int[] mNestedOffsets = new int[2];
+
+    /**
+     * These are views that had their a11y importance changed during a layout. We defer these events
+     * until the end of the layout because a11y service may make sync calls back to the RV while
+     * the View's state is undefined.
+     */
+    @VisibleForTesting
+    final List<ViewHolder> mPendingAccessibilityImportanceChange = new ArrayList();
+
+    private Runnable mItemAnimatorRunner = new Runnable() {
+        @Override
+        public void run() {
+            if (mItemAnimator != null) {
+                mItemAnimator.runPendingAnimations();
+            }
+            mPostedAnimatorRunner = false;
+        }
+    };
+
+    static final Interpolator sQuinticInterpolator = new Interpolator() {
+        @Override
+        public float getInterpolation(float t) {
+            t -= 1.0f;
+            return t * t * t * t * t + 1.0f;
+        }
+    };
+
+    /**
+     * The callback to convert view info diffs into animations.
+     */
+    private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback =
+            new ViewInfoStore.ProcessCallback() {
+        @Override
+        public void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo info,
+                @Nullable ItemHolderInfo postInfo) {
+            mRecycler.unscrapView(viewHolder);
+            animateDisappearance(viewHolder, info, postInfo);
+        }
+        @Override
+        public void processAppeared(ViewHolder viewHolder,
+                ItemHolderInfo preInfo, ItemHolderInfo info) {
+            animateAppearance(viewHolder, preInfo, info);
+        }
+
+        @Override
+        public void processPersistent(ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            viewHolder.setIsRecyclable(false);
+            if (mDataSetHasChangedAfterLayout) {
+                // since it was rebound, use change instead as we'll be mapping them from
+                // stable ids. If stable ids were false, we would not be running any
+                // animations
+                if (mItemAnimator.animateChange(viewHolder, viewHolder, preInfo, postInfo)) {
+                    postAnimationRunner();
+                }
+            } else if (mItemAnimator.animatePersistence(viewHolder, preInfo, postInfo)) {
+                postAnimationRunner();
+            }
+        }
+        @Override
+        public void unused(ViewHolder viewHolder) {
+            mLayout.removeAndRecycleView(viewHolder.itemView, mRecycler);
+        }
+    };
+
+    public RecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public RecyclerView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        if (attrs != null) {
+            TypedArray a = context.obtainStyledAttributes(attrs, CLIP_TO_PADDING_ATTR, defStyle, 0);
+            mClipToPadding = a.getBoolean(0, true);
+            a.recycle();
+        } else {
+            mClipToPadding = true;
+        }
+        setScrollContainer(true);
+        setFocusableInTouchMode(true);
+
+        final ViewConfiguration vc = ViewConfiguration.get(context);
+        mTouchSlop = vc.getScaledTouchSlop();
+        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
+        mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+        setWillNotDraw(getOverScrollMode() == View.OVER_SCROLL_NEVER);
+
+        mItemAnimator.setListener(mItemAnimatorListener);
+        initAdapterManager();
+        initChildrenHelper();
+        // If not explicitly specified this view is important for accessibility.
+        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+        mAccessibilityManager = (AccessibilityManager) getContext()
+                .getSystemService(Context.ACCESSIBILITY_SERVICE);
+        setAccessibilityDelegateCompat(new RecyclerViewAccessibilityDelegate(this));
+        // Create the layoutManager if specified.
+
+        boolean nestedScrollingEnabled = true;
+
+        if (attrs != null) {
+            int defStyleRes = 0;
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecyclerView,
+                    defStyle, defStyleRes);
+            String layoutManagerName = a.getString(R.styleable.RecyclerView_layoutManager);
+            int descendantFocusability = a.getInt(
+                    R.styleable.RecyclerView_descendantFocusability, -1);
+            if (descendantFocusability == -1) {
+                setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+            }
+            a.recycle();
+            createLayoutManager(context, layoutManagerName, attrs, defStyle, defStyleRes);
+
+            if (Build.VERSION.SDK_INT >= 21) {
+                a = context.obtainStyledAttributes(attrs, NESTED_SCROLLING_ATTRS,
+                        defStyle, defStyleRes);
+                nestedScrollingEnabled = a.getBoolean(0, true);
+                a.recycle();
+            }
+        } else {
+            setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+        }
+
+        // Re-set whether nested scrolling is enabled so that it is set on all API levels
+        setNestedScrollingEnabled(nestedScrollingEnabled);
+    }
+
+    /**
+     * Returns the accessibility delegate compatibility implementation used by the RecyclerView.
+     * @return An instance of AccessibilityDelegateCompat used by RecyclerView
+     */
+    public RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate() {
+        return mAccessibilityDelegate;
+    }
+
+    /**
+     * Sets the accessibility delegate compatibility implementation used by RecyclerView.
+     * @param accessibilityDelegate The accessibility delegate to be used by RecyclerView.
+     */
+    public void setAccessibilityDelegateCompat(
+            RecyclerViewAccessibilityDelegate accessibilityDelegate) {
+        mAccessibilityDelegate = accessibilityDelegate;
+        setAccessibilityDelegate(mAccessibilityDelegate);
+    }
+
+    /**
+     * Instantiate and set a LayoutManager, if specified in the attributes.
+     */
+    private void createLayoutManager(Context context, String className, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        if (className != null) {
+            className = className.trim();
+            if (className.length() != 0) {  // Can't use isEmpty since it was added in API 9.
+                className = getFullClassName(context, className);
+                try {
+                    ClassLoader classLoader;
+                    if (isInEditMode()) {
+                        // Stupid layoutlib cannot handle simple class loaders.
+                        classLoader = this.getClass().getClassLoader();
+                    } else {
+                        classLoader = context.getClassLoader();
+                    }
+                    Class<? extends LayoutManager> layoutManagerClass =
+                            classLoader.loadClass(className).asSubclass(LayoutManager.class);
+                    Constructor<? extends LayoutManager> constructor;
+                    Object[] constructorArgs = null;
+                    try {
+                        constructor = layoutManagerClass
+                                .getConstructor(LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE);
+                        constructorArgs = new Object[]{context, attrs, defStyleAttr, defStyleRes};
+                    } catch (NoSuchMethodException e) {
+                        try {
+                            constructor = layoutManagerClass.getConstructor();
+                        } catch (NoSuchMethodException e1) {
+                            e1.initCause(e);
+                            throw new IllegalStateException(attrs.getPositionDescription()
+                                    + ": Error creating LayoutManager " + className, e1);
+                        }
+                    }
+                    constructor.setAccessible(true);
+                    setLayoutManager(constructor.newInstance(constructorArgs));
+                } catch (ClassNotFoundException e) {
+                    throw new IllegalStateException(attrs.getPositionDescription()
+                            + ": Unable to find LayoutManager " + className, e);
+                } catch (InvocationTargetException e) {
+                    throw new IllegalStateException(attrs.getPositionDescription()
+                            + ": Could not instantiate the LayoutManager: " + className, e);
+                } catch (InstantiationException e) {
+                    throw new IllegalStateException(attrs.getPositionDescription()
+                            + ": Could not instantiate the LayoutManager: " + className, e);
+                } catch (IllegalAccessException e) {
+                    throw new IllegalStateException(attrs.getPositionDescription()
+                            + ": Cannot access non-public constructor " + className, e);
+                } catch (ClassCastException e) {
+                    throw new IllegalStateException(attrs.getPositionDescription()
+                            + ": Class is not a LayoutManager " + className, e);
+                }
+            }
+        }
+    }
+
+    private String getFullClassName(Context context, String className) {
+        if (className.charAt(0) == '.') {
+            return context.getPackageName() + className;
+        }
+        if (className.contains(".")) {
+            return className;
+        }
+        return RecyclerView.class.getPackage().getName() + '.' + className;
+    }
+
+    private void initChildrenHelper() {
+        mChildHelper = new ChildHelper(new ChildHelper.Callback() {
+            @Override
+            public int getChildCount() {
+                return RecyclerView.this.getChildCount();
+            }
+
+            @Override
+            public void addView(View child, int index) {
+                RecyclerView.this.addView(child, index);
+                dispatchChildAttached(child);
+            }
+
+            @Override
+            public int indexOfChild(View view) {
+                return RecyclerView.this.indexOfChild(view);
+            }
+
+            @Override
+            public void removeViewAt(int index) {
+                final View child = RecyclerView.this.getChildAt(index);
+                if (child != null) {
+                    dispatchChildDetached(child);
+                }
+                RecyclerView.this.removeViewAt(index);
+            }
+
+            @Override
+            public View getChildAt(int offset) {
+                return RecyclerView.this.getChildAt(offset);
+            }
+
+            @Override
+            public void removeAllViews() {
+                final int count = getChildCount();
+                for (int i = 0; i < count; i++) {
+                    dispatchChildDetached(getChildAt(i));
+                }
+                RecyclerView.this.removeAllViews();
+            }
+
+            @Override
+            public ViewHolder getChildViewHolder(View view) {
+                return getChildViewHolderInt(view);
+            }
+
+            @Override
+            public void attachViewToParent(View child, int index,
+                    ViewGroup.LayoutParams layoutParams) {
+                final ViewHolder vh = getChildViewHolderInt(child);
+                if (vh != null) {
+                    if (!vh.isTmpDetached() && !vh.shouldIgnore()) {
+                        throw new IllegalArgumentException("Called attach on a child which is not"
+                                + " detached: " + vh);
+                    }
+                    if (DEBUG) {
+                        Log.d(TAG, "reAttach " + vh);
+                    }
+                    vh.clearTmpDetachFlag();
+                }
+                RecyclerView.this.attachViewToParent(child, index, layoutParams);
+            }
+
+            @Override
+            public void detachViewFromParent(int offset) {
+                final View view = getChildAt(offset);
+                if (view != null) {
+                    final ViewHolder vh = getChildViewHolderInt(view);
+                    if (vh != null) {
+                        if (vh.isTmpDetached() && !vh.shouldIgnore()) {
+                            throw new IllegalArgumentException("called detach on an already"
+                                    + " detached child " + vh);
+                        }
+                        if (DEBUG) {
+                            Log.d(TAG, "tmpDetach " + vh);
+                        }
+                        vh.addFlags(ViewHolder.FLAG_TMP_DETACHED);
+                    }
+                }
+                RecyclerView.this.detachViewFromParent(offset);
+            }
+
+            @Override
+            public void onEnteredHiddenState(View child) {
+                final ViewHolder vh = getChildViewHolderInt(child);
+                if (vh != null) {
+                    vh.onEnteredHiddenState(RecyclerView.this);
+                }
+            }
+
+            @Override
+            public void onLeftHiddenState(View child) {
+                final ViewHolder vh = getChildViewHolderInt(child);
+                if (vh != null) {
+                    vh.onLeftHiddenState(RecyclerView.this);
+                }
+            }
+        });
+    }
+
+    void initAdapterManager() {
+        mAdapterHelper = new AdapterHelper(new AdapterHelper.Callback() {
+            @Override
+            public ViewHolder findViewHolder(int position) {
+                final ViewHolder vh = findViewHolderForPosition(position, true);
+                if (vh == null) {
+                    return null;
+                }
+                // ensure it is not hidden because for adapter helper, the only thing matter is that
+                // LM thinks view is a child.
+                if (mChildHelper.isHidden(vh.itemView)) {
+                    if (DEBUG) {
+                        Log.d(TAG, "assuming view holder cannot be find because it is hidden");
+                    }
+                    return null;
+                }
+                return vh;
+            }
+
+            @Override
+            public void offsetPositionsForRemovingInvisible(int start, int count) {
+                offsetPositionRecordsForRemove(start, count, true);
+                mItemsAddedOrRemoved = true;
+                mState.mDeletedInvisibleItemCountSincePreviousLayout += count;
+            }
+
+            @Override
+            public void offsetPositionsForRemovingLaidOutOrNewView(
+                    int positionStart, int itemCount) {
+                offsetPositionRecordsForRemove(positionStart, itemCount, false);
+                mItemsAddedOrRemoved = true;
+            }
+
+            @Override
+            public void markViewHoldersUpdated(int positionStart, int itemCount, Object payload) {
+                viewRangeUpdate(positionStart, itemCount, payload);
+                mItemsChanged = true;
+            }
+
+            @Override
+            public void onDispatchFirstPass(AdapterHelper.UpdateOp op) {
+                dispatchUpdate(op);
+            }
+
+            void dispatchUpdate(AdapterHelper.UpdateOp op) {
+                switch (op.cmd) {
+                    case AdapterHelper.UpdateOp.ADD:
+                        mLayout.onItemsAdded(RecyclerView.this, op.positionStart, op.itemCount);
+                        break;
+                    case AdapterHelper.UpdateOp.REMOVE:
+                        mLayout.onItemsRemoved(RecyclerView.this, op.positionStart, op.itemCount);
+                        break;
+                    case AdapterHelper.UpdateOp.UPDATE:
+                        mLayout.onItemsUpdated(RecyclerView.this, op.positionStart, op.itemCount,
+                                op.payload);
+                        break;
+                    case AdapterHelper.UpdateOp.MOVE:
+                        mLayout.onItemsMoved(RecyclerView.this, op.positionStart, op.itemCount, 1);
+                        break;
+                }
+            }
+
+            @Override
+            public void onDispatchSecondPass(AdapterHelper.UpdateOp op) {
+                dispatchUpdate(op);
+            }
+
+            @Override
+            public void offsetPositionsForAdd(int positionStart, int itemCount) {
+                offsetPositionRecordsForInsert(positionStart, itemCount);
+                mItemsAddedOrRemoved = true;
+            }
+
+            @Override
+            public void offsetPositionsForMove(int from, int to) {
+                offsetPositionRecordsForMove(from, to);
+                // should we create mItemsMoved ?
+                mItemsAddedOrRemoved = true;
+            }
+        });
+    }
+
+    /**
+     * RecyclerView can perform several optimizations if it can know in advance that RecyclerView's
+     * size is not affected by the adapter contents. RecyclerView can still change its size based
+     * on other factors (e.g. its parent's size) but this size calculation cannot depend on the
+     * size of its children or contents of its adapter (except the number of items in the adapter).
+     * <p>
+     * If your use of RecyclerView falls into this category, set this to {@code true}. It will allow
+     * RecyclerView to avoid invalidating the whole layout when its adapter contents change.
+     *
+     * @param hasFixedSize true if adapter changes cannot affect the size of the RecyclerView.
+     */
+    public void setHasFixedSize(boolean hasFixedSize) {
+        mHasFixedSize = hasFixedSize;
+    }
+
+    /**
+     * @return true if the app has specified that changes in adapter content cannot change
+     * the size of the RecyclerView itself.
+     */
+    public boolean hasFixedSize() {
+        return mHasFixedSize;
+    }
+
+    @Override
+    public void setClipToPadding(boolean clipToPadding) {
+        if (clipToPadding != mClipToPadding) {
+            invalidateGlows();
+        }
+        mClipToPadding = clipToPadding;
+        super.setClipToPadding(clipToPadding);
+        if (mFirstLayoutComplete) {
+            requestLayout();
+        }
+    }
+
+    /**
+     * Returns whether this RecyclerView will clip its children to its padding, and resize (but
+     * not clip) any EdgeEffect to the padded region, if padding is present.
+     * <p>
+     * By default, children are clipped to the padding of their parent
+     * RecyclerView. This clipping behavior is only enabled if padding is non-zero.
+     *
+     * @return true if this RecyclerView clips children to its padding and resizes (but doesn't
+     *         clip) any EdgeEffect to the padded region, false otherwise.
+     *
+     * @attr name android:clipToPadding
+     */
+    @Override
+    public boolean getClipToPadding() {
+        return mClipToPadding;
+    }
+
+    /**
+     * Configure the scrolling touch slop for a specific use case.
+     *
+     * Set up the RecyclerView's scrolling motion threshold based on common usages.
+     * Valid arguments are {@link #TOUCH_SLOP_DEFAULT} and {@link #TOUCH_SLOP_PAGING}.
+     *
+     * @param slopConstant One of the <code>TOUCH_SLOP_</code> constants representing
+     *                     the intended usage of this RecyclerView
+     */
+    public void setScrollingTouchSlop(int slopConstant) {
+        final ViewConfiguration vc = ViewConfiguration.get(getContext());
+        switch (slopConstant) {
+            default:
+                Log.w(TAG, "setScrollingTouchSlop(): bad argument constant "
+                        + slopConstant + "; using default value");
+                // fall-through
+            case TOUCH_SLOP_DEFAULT:
+                mTouchSlop = vc.getScaledTouchSlop();
+                break;
+
+            case TOUCH_SLOP_PAGING:
+                mTouchSlop = vc.getScaledPagingTouchSlop();
+                break;
+        }
+    }
+
+    /**
+     * Swaps the current adapter with the provided one. It is similar to
+     * {@link #setAdapter(Adapter)} but assumes existing adapter and the new adapter uses the same
+     * {@link ViewHolder} and does not clear the RecycledViewPool.
+     * <p>
+     * Note that it still calls onAdapterChanged callbacks.
+     *
+     * @param adapter The new adapter to set, or null to set no adapter.
+     * @param removeAndRecycleExistingViews If set to true, RecyclerView will recycle all existing
+     *                                      Views. If adapters have stable ids and/or you want to
+     *                                      animate the disappearing views, you may prefer to set
+     *                                      this to false.
+     * @see #setAdapter(Adapter)
+     */
+    public void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews) {
+        // bail out if layout is frozen
+        setLayoutFrozen(false);
+        setAdapterInternal(adapter, true, removeAndRecycleExistingViews);
+        setDataSetChangedAfterLayout();
+        requestLayout();
+    }
+    /**
+     * Set a new adapter to provide child views on demand.
+     * <p>
+     * When adapter is changed, all existing views are recycled back to the pool. If the pool has
+     * only one adapter, it will be cleared.
+     *
+     * @param adapter The new adapter to set, or null to set no adapter.
+     * @see #swapAdapter(Adapter, boolean)
+     */
+    public void setAdapter(Adapter adapter) {
+        // bail out if layout is frozen
+        setLayoutFrozen(false);
+        setAdapterInternal(adapter, false, true);
+        requestLayout();
+    }
+
+    /**
+     * Removes and recycles all views - both those currently attached, and those in the Recycler.
+     */
+    void removeAndRecycleViews() {
+        // end all running animations
+        if (mItemAnimator != null) {
+            mItemAnimator.endAnimations();
+        }
+        // Since animations are ended, mLayout.children should be equal to
+        // recyclerView.children. This may not be true if item animator's end does not work as
+        // expected. (e.g. not release children instantly). It is safer to use mLayout's child
+        // count.
+        if (mLayout != null) {
+            mLayout.removeAndRecycleAllViews(mRecycler);
+            mLayout.removeAndRecycleScrapInt(mRecycler);
+        }
+        // we should clear it here before adapters are swapped to ensure correct callbacks.
+        mRecycler.clear();
+    }
+
+    /**
+     * Replaces the current adapter with the new one and triggers listeners.
+     * @param adapter The new adapter
+     * @param compatibleWithPrevious If true, the new adapter is using the same View Holders and
+     *                               item types with the current adapter (helps us avoid cache
+     *                               invalidation).
+     * @param removeAndRecycleViews  If true, we'll remove and recycle all existing views. If
+     *                               compatibleWithPrevious is false, this parameter is ignored.
+     */
+    private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
+            boolean removeAndRecycleViews) {
+        if (mAdapter != null) {
+            mAdapter.unregisterAdapterDataObserver(mObserver);
+            mAdapter.onDetachedFromRecyclerView(this);
+        }
+        if (!compatibleWithPrevious || removeAndRecycleViews) {
+            removeAndRecycleViews();
+        }
+        mAdapterHelper.reset();
+        final Adapter oldAdapter = mAdapter;
+        mAdapter = adapter;
+        if (adapter != null) {
+            adapter.registerAdapterDataObserver(mObserver);
+            adapter.onAttachedToRecyclerView(this);
+        }
+        if (mLayout != null) {
+            mLayout.onAdapterChanged(oldAdapter, mAdapter);
+        }
+        mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
+        mState.mStructureChanged = true;
+        markKnownViewsInvalid();
+    }
+
+    /**
+     * Retrieves the previously set adapter or null if no adapter is set.
+     *
+     * @return The previously set adapter
+     * @see #setAdapter(Adapter)
+     */
+    public Adapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Register a listener that will be notified whenever a child view is recycled.
+     *
+     * <p>This listener will be called when a LayoutManager or the RecyclerView decides
+     * that a child view is no longer needed. If an application associates expensive
+     * or heavyweight data with item views, this may be a good place to release
+     * or free those resources.</p>
+     *
+     * @param listener Listener to register, or null to clear
+     */
+    public void setRecyclerListener(RecyclerListener listener) {
+        mRecyclerListener = listener;
+    }
+
+    /**
+     * <p>Return the offset of the RecyclerView's text baseline from the its top
+     * boundary. If the LayoutManager of this RecyclerView does not support baseline alignment,
+     * this method returns -1.</p>
+     *
+     * @return the offset of the baseline within the RecyclerView's bounds or -1
+     *         if baseline alignment is not supported
+     */
+    @Override
+    public int getBaseline() {
+        if (mLayout != null) {
+            return mLayout.getBaseline();
+        } else {
+            return super.getBaseline();
+        }
+    }
+
+    /**
+     * Register a listener that will be notified whenever a child view is attached to or detached
+     * from RecyclerView.
+     *
+     * <p>This listener will be called when a LayoutManager or the RecyclerView decides
+     * that a child view is no longer needed. If an application associates expensive
+     * or heavyweight data with item views, this may be a good place to release
+     * or free those resources.</p>
+     *
+     * @param listener Listener to register
+     */
+    public void addOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) {
+        if (mOnChildAttachStateListeners == null) {
+            mOnChildAttachStateListeners = new ArrayList<>();
+        }
+        mOnChildAttachStateListeners.add(listener);
+    }
+
+    /**
+     * Removes the provided listener from child attached state listeners list.
+     *
+     * @param listener Listener to unregister
+     */
+    public void removeOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) {
+        if (mOnChildAttachStateListeners == null) {
+            return;
+        }
+        mOnChildAttachStateListeners.remove(listener);
+    }
+
+    /**
+     * Removes all listeners that were added via
+     * {@link #addOnChildAttachStateChangeListener(OnChildAttachStateChangeListener)}.
+     */
+    public void clearOnChildAttachStateChangeListeners() {
+        if (mOnChildAttachStateListeners != null) {
+            mOnChildAttachStateListeners.clear();
+        }
+    }
+
+    /**
+     * Set the {@link LayoutManager} that this RecyclerView will use.
+     *
+     * <p>In contrast to other adapter-backed views such as {@link android.widget.ListView}
+     * or {@link android.widget.GridView}, RecyclerView allows client code to provide custom
+     * layout arrangements for child views. These arrangements are controlled by the
+     * {@link LayoutManager}. A LayoutManager must be provided for RecyclerView to function.</p>
+     *
+     * <p>Several default strategies are provided for common uses such as lists and grids.</p>
+     *
+     * @param layout LayoutManager to use
+     */
+    public void setLayoutManager(LayoutManager layout) {
+        if (layout == mLayout) {
+            return;
+        }
+        stopScroll();
+        // TODO We should do this switch a dispatchLayout pass and animate children. There is a good
+        // chance that LayoutManagers will re-use views.
+        if (mLayout != null) {
+            // end all running animations
+            if (mItemAnimator != null) {
+                mItemAnimator.endAnimations();
+            }
+            mLayout.removeAndRecycleAllViews(mRecycler);
+            mLayout.removeAndRecycleScrapInt(mRecycler);
+            mRecycler.clear();
+
+            if (mIsAttached) {
+                mLayout.dispatchDetachedFromWindow(this, mRecycler);
+            }
+            mLayout.setRecyclerView(null);
+            mLayout = null;
+        } else {
+            mRecycler.clear();
+        }
+        // this is just a defensive measure for faulty item animators.
+        mChildHelper.removeAllViewsUnfiltered();
+        mLayout = layout;
+        if (layout != null) {
+            if (layout.mRecyclerView != null) {
+                throw new IllegalArgumentException("LayoutManager " + layout
+                        + " is already attached to a RecyclerView: " + layout.mRecyclerView);
+            }
+            mLayout.setRecyclerView(this);
+            if (mIsAttached) {
+                mLayout.dispatchAttachedToWindow(this);
+            }
+        }
+        mRecycler.updateViewCacheSize();
+        requestLayout();
+    }
+
+    /**
+     * Set a {@link OnFlingListener} for this {@link RecyclerView}.
+     * <p>
+     * If the {@link OnFlingListener} is set then it will receive
+     * calls to {@link #fling(int,int)} and will be able to intercept them.
+     *
+     * @param onFlingListener The {@link OnFlingListener} instance.
+     */
+    public void setOnFlingListener(@Nullable OnFlingListener onFlingListener) {
+        mOnFlingListener = onFlingListener;
+    }
+
+    /**
+     * Get the current {@link OnFlingListener} from this {@link RecyclerView}.
+     *
+     * @return The {@link OnFlingListener} instance currently set (can be null).
+     */
+    @Nullable
+    public OnFlingListener getOnFlingListener() {
+        return mOnFlingListener;
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        SavedState state = new SavedState(super.onSaveInstanceState());
+        if (mPendingSavedState != null) {
+            state.copyFrom(mPendingSavedState);
+        } else if (mLayout != null) {
+            state.mLayoutState = mLayout.onSaveInstanceState();
+        } else {
+            state.mLayoutState = null;
+        }
+
+        return state;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        mPendingSavedState = (SavedState) state;
+        super.onRestoreInstanceState(mPendingSavedState.getSuperState());
+        if (mLayout != null && mPendingSavedState.mLayoutState != null) {
+            mLayout.onRestoreInstanceState(mPendingSavedState.mLayoutState);
+        }
+    }
+
+    /**
+     * Override to prevent freezing of any views created by the adapter.
+     */
+    @Override
+    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
+        dispatchFreezeSelfOnly(container);
+    }
+
+    /**
+     * Override to prevent thawing of any views created by the adapter.
+     */
+    @Override
+    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
+        dispatchThawSelfOnly(container);
+    }
+
+    /**
+     * Adds a view to the animatingViews list.
+     * mAnimatingViews holds the child views that are currently being kept around
+     * purely for the purpose of being animated out of view. They are drawn as a regular
+     * part of the child list of the RecyclerView, but they are invisible to the LayoutManager
+     * as they are managed separately from the regular child views.
+     * @param viewHolder The ViewHolder to be removed
+     */
+    private void addAnimatingView(ViewHolder viewHolder) {
+        final View view = viewHolder.itemView;
+        final boolean alreadyParented = view.getParent() == this;
+        mRecycler.unscrapView(getChildViewHolder(view));
+        if (viewHolder.isTmpDetached()) {
+            // re-attach
+            mChildHelper.attachViewToParent(view, -1, view.getLayoutParams(), true);
+        } else if (!alreadyParented) {
+            mChildHelper.addView(view, true);
+        } else {
+            mChildHelper.hide(view);
+        }
+    }
+
+    /**
+     * Removes a view from the animatingViews list.
+     * @param view The view to be removed
+     * @see #addAnimatingView(RecyclerView.ViewHolder)
+     * @return true if an animating view is removed
+     */
+    boolean removeAnimatingView(View view) {
+        eatRequestLayout();
+        final boolean removed = mChildHelper.removeViewIfHidden(view);
+        if (removed) {
+            final ViewHolder viewHolder = getChildViewHolderInt(view);
+            mRecycler.unscrapView(viewHolder);
+            mRecycler.recycleViewHolderInternal(viewHolder);
+            if (DEBUG) {
+                Log.d(TAG, "after removing animated view: " + view + ", " + this);
+            }
+        }
+        // only clear request eaten flag if we removed the view.
+        resumeRequestLayout(!removed);
+        return removed;
+    }
+
+    /**
+     * Return the {@link LayoutManager} currently responsible for
+     * layout policy for this RecyclerView.
+     *
+     * @return The currently bound LayoutManager
+     */
+    public LayoutManager getLayoutManager() {
+        return mLayout;
+    }
+
+    /**
+     * Retrieve this RecyclerView's {@link RecycledViewPool}. This method will never return null;
+     * if no pool is set for this view a new one will be created. See
+     * {@link #setRecycledViewPool(RecycledViewPool) setRecycledViewPool} for more information.
+     *
+     * @return The pool used to store recycled item views for reuse.
+     * @see #setRecycledViewPool(RecycledViewPool)
+     */
+    public RecycledViewPool getRecycledViewPool() {
+        return mRecycler.getRecycledViewPool();
+    }
+
+    /**
+     * Recycled view pools allow multiple RecyclerViews to share a common pool of scrap views.
+     * This can be useful if you have multiple RecyclerViews with adapters that use the same
+     * view types, for example if you have several data sets with the same kinds of item views
+     * displayed by a {@link android.support.v4.view.ViewPager ViewPager}.
+     *
+     * @param pool Pool to set. If this parameter is null a new pool will be created and used.
+     */
+    public void setRecycledViewPool(RecycledViewPool pool) {
+        mRecycler.setRecycledViewPool(pool);
+    }
+
+    /**
+     * Sets a new {@link ViewCacheExtension} to be used by the Recycler.
+     *
+     * @param extension ViewCacheExtension to be used or null if you want to clear the existing one.
+     *
+     * @see {@link ViewCacheExtension#getViewForPositionAndType(Recycler, int, int)}
+     */
+    public void setViewCacheExtension(ViewCacheExtension extension) {
+        mRecycler.setViewCacheExtension(extension);
+    }
+
+    /**
+     * Set the number of offscreen views to retain before adding them to the potentially shared
+     * {@link #getRecycledViewPool() recycled view pool}.
+     *
+     * <p>The offscreen view cache stays aware of changes in the attached adapter, allowing
+     * a LayoutManager to reuse those views unmodified without needing to return to the adapter
+     * to rebind them.</p>
+     *
+     * @param size Number of views to cache offscreen before returning them to the general
+     *             recycled view pool
+     */
+    public void setItemViewCacheSize(int size) {
+        mRecycler.setViewCacheSize(size);
+    }
+
+    /**
+     * Return the current scrolling state of the RecyclerView.
+     *
+     * @return {@link #SCROLL_STATE_IDLE}, {@link #SCROLL_STATE_DRAGGING} or
+     * {@link #SCROLL_STATE_SETTLING}
+     */
+    public int getScrollState() {
+        return mScrollState;
+    }
+
+    void setScrollState(int state) {
+        if (state == mScrollState) {
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "setting scroll state to " + state + " from " + mScrollState,
+                    new Exception());
+        }
+        mScrollState = state;
+        if (state != SCROLL_STATE_SETTLING) {
+            stopScrollersInternal();
+        }
+        dispatchOnScrollStateChanged(state);
+    }
+
+    /**
+     * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can
+     * affect both measurement and drawing of individual item views.
+     *
+     * <p>Item decorations are ordered. Decorations placed earlier in the list will
+     * be run/queried/drawn first for their effects on item views. Padding added to views
+     * will be nested; a padding added by an earlier decoration will mean further
+     * item decorations in the list will be asked to draw/pad within the previous decoration's
+     * given area.</p>
+     *
+     * @param decor Decoration to add
+     * @param index Position in the decoration chain to insert this decoration at. If this value
+     *              is negative the decoration will be added at the end.
+     */
+    public void addItemDecoration(ItemDecoration decor, int index) {
+        if (mLayout != null) {
+            mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll  or"
+                    + " layout");
+        }
+        if (mItemDecorations.isEmpty()) {
+            setWillNotDraw(false);
+        }
+        if (index < 0) {
+            mItemDecorations.add(decor);
+        } else {
+            mItemDecorations.add(index, decor);
+        }
+        markItemDecorInsetsDirty();
+        requestLayout();
+    }
+
+    /**
+     * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can
+     * affect both measurement and drawing of individual item views.
+     *
+     * <p>Item decorations are ordered. Decorations placed earlier in the list will
+     * be run/queried/drawn first for their effects on item views. Padding added to views
+     * will be nested; a padding added by an earlier decoration will mean further
+     * item decorations in the list will be asked to draw/pad within the previous decoration's
+     * given area.</p>
+     *
+     * @param decor Decoration to add
+     */
+    public void addItemDecoration(ItemDecoration decor) {
+        addItemDecoration(decor, -1);
+    }
+
+    /**
+     * Remove an {@link ItemDecoration} from this RecyclerView.
+     *
+     * <p>The given decoration will no longer impact the measurement and drawing of
+     * item views.</p>
+     *
+     * @param decor Decoration to remove
+     * @see #addItemDecoration(ItemDecoration)
+     */
+    public void removeItemDecoration(ItemDecoration decor) {
+        if (mLayout != null) {
+            mLayout.assertNotInLayoutOrScroll("Cannot remove item decoration during a scroll  or"
+                    + " layout");
+        }
+        mItemDecorations.remove(decor);
+        if (mItemDecorations.isEmpty()) {
+            setWillNotDraw(getOverScrollMode() == View.OVER_SCROLL_NEVER);
+        }
+        markItemDecorInsetsDirty();
+        requestLayout();
+    }
+
+    /**
+     * Sets the {@link ChildDrawingOrderCallback} to be used for drawing children.
+     * <p>
+     * See {@link ViewGroup#getChildDrawingOrder(int, int)} for details. Calling this method will
+     * always call {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean)}. The parameter will be
+     * true if childDrawingOrderCallback is not null, false otherwise.
+     * <p>
+     * Note that child drawing order may be overridden by View's elevation.
+     *
+     * @param childDrawingOrderCallback The ChildDrawingOrderCallback to be used by the drawing
+     *                                  system.
+     */
+    public void setChildDrawingOrderCallback(ChildDrawingOrderCallback childDrawingOrderCallback) {
+        if (childDrawingOrderCallback == mChildDrawingOrderCallback) {
+            return;
+        }
+        mChildDrawingOrderCallback = childDrawingOrderCallback;
+        setChildrenDrawingOrderEnabled(mChildDrawingOrderCallback != null);
+    }
+
+    /**
+     * Set a listener that will be notified of any changes in scroll state or position.
+     *
+     * @param listener Listener to set or null to clear
+     *
+     * @deprecated Use {@link #addOnScrollListener(OnScrollListener)} and
+     *             {@link #removeOnScrollListener(OnScrollListener)}
+     */
+    @Deprecated
+    public void setOnScrollListener(OnScrollListener listener) {
+        mScrollListener = listener;
+    }
+
+    /**
+     * Add a listener that will be notified of any changes in scroll state or position.
+     *
+     * <p>Components that add a listener should take care to remove it when finished.
+     * Other components that take ownership of a view may call {@link #clearOnScrollListeners()}
+     * to remove all attached listeners.</p>
+     *
+     * @param listener listener to set or null to clear
+     */
+    public void addOnScrollListener(OnScrollListener listener) {
+        if (mScrollListeners == null) {
+            mScrollListeners = new ArrayList<>();
+        }
+        mScrollListeners.add(listener);
+    }
+
+    /**
+     * Remove a listener that was notified of any changes in scroll state or position.
+     *
+     * @param listener listener to set or null to clear
+     */
+    public void removeOnScrollListener(OnScrollListener listener) {
+        if (mScrollListeners != null) {
+            mScrollListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Remove all secondary listener that were notified of any changes in scroll state or position.
+     */
+    public void clearOnScrollListeners() {
+        if (mScrollListeners != null) {
+            mScrollListeners.clear();
+        }
+    }
+
+    /**
+     * Convenience method to scroll to a certain position.
+     *
+     * RecyclerView does not implement scrolling logic, rather forwards the call to
+     * {@link com.android.internal.widget.RecyclerView.LayoutManager#scrollToPosition(int)}
+     * @param position Scroll to this adapter position
+     * @see com.android.internal.widget.RecyclerView.LayoutManager#scrollToPosition(int)
+     */
+    public void scrollToPosition(int position) {
+        if (mLayoutFrozen) {
+            return;
+        }
+        stopScroll();
+        if (mLayout == null) {
+            Log.e(TAG, "Cannot scroll to position a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
+            return;
+        }
+        mLayout.scrollToPosition(position);
+        awakenScrollBars();
+    }
+
+    void jumpToPositionForSmoothScroller(int position) {
+        if (mLayout == null) {
+            return;
+        }
+        mLayout.scrollToPosition(position);
+        awakenScrollBars();
+    }
+
+    /**
+     * Starts a smooth scroll to an adapter position.
+     * <p>
+     * To support smooth scrolling, you must override
+     * {@link LayoutManager#smoothScrollToPosition(RecyclerView, State, int)} and create a
+     * {@link SmoothScroller}.
+     * <p>
+     * {@link LayoutManager} is responsible for creating the actual scroll action. If you want to
+     * provide a custom smooth scroll logic, override
+     * {@link LayoutManager#smoothScrollToPosition(RecyclerView, State, int)} in your
+     * LayoutManager.
+     *
+     * @param position The adapter position to scroll to
+     * @see LayoutManager#smoothScrollToPosition(RecyclerView, State, int)
+     */
+    public void smoothScrollToPosition(int position) {
+        if (mLayoutFrozen) {
+            return;
+        }
+        if (mLayout == null) {
+            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
+            return;
+        }
+        mLayout.smoothScrollToPosition(this, mState, position);
+    }
+
+    @Override
+    public void scrollTo(int x, int y) {
+        Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. "
+                + "Use scrollToPosition instead");
+    }
+
+    @Override
+    public void scrollBy(int x, int y) {
+        if (mLayout == null) {
+            Log.e(TAG, "Cannot scroll without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
+            return;
+        }
+        if (mLayoutFrozen) {
+            return;
+        }
+        final boolean canScrollHorizontal = mLayout.canScrollHorizontally();
+        final boolean canScrollVertical = mLayout.canScrollVertically();
+        if (canScrollHorizontal || canScrollVertical) {
+            scrollByInternal(canScrollHorizontal ? x : 0, canScrollVertical ? y : 0, null);
+        }
+    }
+
+    /**
+     * Helper method reflect data changes to the state.
+     * <p>
+     * Adapter changes during a scroll may trigger a crash because scroll assumes no data change
+     * but data actually changed.
+     * <p>
+     * This method consumes all deferred changes to avoid that case.
+     */
+    void consumePendingUpdateOperations() {
+        if (!mFirstLayoutComplete || mDataSetHasChangedAfterLayout) {
+            Trace.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
+            dispatchLayout();
+            Trace.endSection();
+            return;
+        }
+        if (!mAdapterHelper.hasPendingUpdates()) {
+            return;
+        }
+
+        // if it is only an item change (no add-remove-notifyDataSetChanged) we can check if any
+        // of the visible items is affected and if not, just ignore the change.
+        if (mAdapterHelper.hasAnyUpdateTypes(AdapterHelper.UpdateOp.UPDATE) && !mAdapterHelper
+                .hasAnyUpdateTypes(AdapterHelper.UpdateOp.ADD | AdapterHelper.UpdateOp.REMOVE
+                        | AdapterHelper.UpdateOp.MOVE)) {
+            Trace.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
+            eatRequestLayout();
+            onEnterLayoutOrScroll();
+            mAdapterHelper.preProcess();
+            if (!mLayoutRequestEaten) {
+                if (hasUpdatedView()) {
+                    dispatchLayout();
+                } else {
+                    // no need to layout, clean state
+                    mAdapterHelper.consumePostponedUpdates();
+                }
+            }
+            resumeRequestLayout(true);
+            onExitLayoutOrScroll();
+            Trace.endSection();
+        } else if (mAdapterHelper.hasPendingUpdates()) {
+            Trace.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
+            dispatchLayout();
+            Trace.endSection();
+        }
+    }
+
+    /**
+     * @return True if an existing view holder needs to be updated
+     */
+    private boolean hasUpdatedView() {
+        final int childCount = mChildHelper.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
+            if (holder == null || holder.shouldIgnore()) {
+                continue;
+            }
+            if (holder.isUpdated()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Does not perform bounds checking. Used by internal methods that have already validated input.
+     * <p>
+     * It also reports any unused scroll request to the related EdgeEffect.
+     *
+     * @param x The amount of horizontal scroll request
+     * @param y The amount of vertical scroll request
+     * @param ev The originating MotionEvent, or null if not from a touch event.
+     *
+     * @return Whether any scroll was consumed in either direction.
+     */
+    boolean scrollByInternal(int x, int y, MotionEvent ev) {
+        int unconsumedX = 0, unconsumedY = 0;
+        int consumedX = 0, consumedY = 0;
+
+        consumePendingUpdateOperations();
+        if (mAdapter != null) {
+            eatRequestLayout();
+            onEnterLayoutOrScroll();
+            Trace.beginSection(TRACE_SCROLL_TAG);
+            if (x != 0) {
+                consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);
+                unconsumedX = x - consumedX;
+            }
+            if (y != 0) {
+                consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);
+                unconsumedY = y - consumedY;
+            }
+            Trace.endSection();
+            repositionShadowingViews();
+            onExitLayoutOrScroll();
+            resumeRequestLayout(false);
+        }
+        if (!mItemDecorations.isEmpty()) {
+            invalidate();
+        }
+
+        if (dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset)) {
+            // Update the last touch co-ords, taking any scroll offset into account
+            mLastTouchX -= mScrollOffset[0];
+            mLastTouchY -= mScrollOffset[1];
+            if (ev != null) {
+                ev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
+            }
+            mNestedOffsets[0] += mScrollOffset[0];
+            mNestedOffsets[1] += mScrollOffset[1];
+        } else if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
+            if (ev != null) {
+                pullGlows(ev.getX(), unconsumedX, ev.getY(), unconsumedY);
+            }
+            considerReleasingGlowsOnScroll(x, y);
+        }
+        if (consumedX != 0 || consumedY != 0) {
+            dispatchOnScrolled(consumedX, consumedY);
+        }
+        if (!awakenScrollBars()) {
+            invalidate();
+        }
+        return consumedX != 0 || consumedY != 0;
+    }
+
+    /**
+     * <p>Compute the horizontal offset of the horizontal scrollbar's thumb within the horizontal
+     * range. This value is used to compute the length of the thumb within the scrollbar's track.
+     * </p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the units used by
+     * {@link #computeHorizontalScrollRange()} and {@link #computeHorizontalScrollExtent()}.</p>
+     *
+     * <p>Default implementation returns 0.</p>
+     *
+     * <p>If you want to support scroll bars, override
+     * {@link RecyclerView.LayoutManager#computeHorizontalScrollOffset(RecyclerView.State)} in your
+     * LayoutManager. </p>
+     *
+     * @return The horizontal offset of the scrollbar's thumb
+     * @see com.android.internal.widget.RecyclerView.LayoutManager#computeHorizontalScrollOffset
+     * (RecyclerView.State)
+     */
+    @Override
+    public int computeHorizontalScrollOffset() {
+        if (mLayout == null) {
+            return 0;
+        }
+        return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollOffset(mState) : 0;
+    }
+
+    /**
+     * <p>Compute the horizontal extent of the horizontal scrollbar's thumb within the
+     * horizontal range. This value is used to compute the length of the thumb within the
+     * scrollbar's track.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the units used by
+     * {@link #computeHorizontalScrollRange()} and {@link #computeHorizontalScrollOffset()}.</p>
+     *
+     * <p>Default implementation returns 0.</p>
+     *
+     * <p>If you want to support scroll bars, override
+     * {@link RecyclerView.LayoutManager#computeHorizontalScrollExtent(RecyclerView.State)} in your
+     * LayoutManager.</p>
+     *
+     * @return The horizontal extent of the scrollbar's thumb
+     * @see RecyclerView.LayoutManager#computeHorizontalScrollExtent(RecyclerView.State)
+     */
+    @Override
+    public int computeHorizontalScrollExtent() {
+        if (mLayout == null) {
+            return 0;
+        }
+        return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollExtent(mState) : 0;
+    }
+
+    /**
+     * <p>Compute the horizontal range that the horizontal scrollbar represents.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the units used by
+     * {@link #computeHorizontalScrollExtent()} and {@link #computeHorizontalScrollOffset()}.</p>
+     *
+     * <p>Default implementation returns 0.</p>
+     *
+     * <p>If you want to support scroll bars, override
+     * {@link RecyclerView.LayoutManager#computeHorizontalScrollRange(RecyclerView.State)} in your
+     * LayoutManager.</p>
+     *
+     * @return The total horizontal range represented by the vertical scrollbar
+     * @see RecyclerView.LayoutManager#computeHorizontalScrollRange(RecyclerView.State)
+     */
+    @Override
+    public int computeHorizontalScrollRange() {
+        if (mLayout == null) {
+            return 0;
+        }
+        return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollRange(mState) : 0;
+    }
+
+    /**
+     * <p>Compute the vertical offset of the vertical scrollbar's thumb within the vertical range.
+     * This value is used to compute the length of the thumb within the scrollbar's track. </p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the units used by
+     * {@link #computeVerticalScrollRange()} and {@link #computeVerticalScrollExtent()}.</p>
+     *
+     * <p>Default implementation returns 0.</p>
+     *
+     * <p>If you want to support scroll bars, override
+     * {@link RecyclerView.LayoutManager#computeVerticalScrollOffset(RecyclerView.State)} in your
+     * LayoutManager.</p>
+     *
+     * @return The vertical offset of the scrollbar's thumb
+     * @see com.android.internal.widget.RecyclerView.LayoutManager#computeVerticalScrollOffset
+     * (RecyclerView.State)
+     */
+    @Override
+    public int computeVerticalScrollOffset() {
+        if (mLayout == null) {
+            return 0;
+        }
+        return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollOffset(mState) : 0;
+    }
+
+    /**
+     * <p>Compute the vertical extent of the vertical scrollbar's thumb within the vertical range.
+     * This value is used to compute the length of the thumb within the scrollbar's track.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the units used by
+     * {@link #computeVerticalScrollRange()} and {@link #computeVerticalScrollOffset()}.</p>
+     *
+     * <p>Default implementation returns 0.</p>
+     *
+     * <p>If you want to support scroll bars, override
+     * {@link RecyclerView.LayoutManager#computeVerticalScrollExtent(RecyclerView.State)} in your
+     * LayoutManager.</p>
+     *
+     * @return The vertical extent of the scrollbar's thumb
+     * @see RecyclerView.LayoutManager#computeVerticalScrollExtent(RecyclerView.State)
+     */
+    @Override
+    public int computeVerticalScrollExtent() {
+        if (mLayout == null) {
+            return 0;
+        }
+        return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollExtent(mState) : 0;
+    }
+
+    /**
+     * <p>Compute the vertical range that the vertical scrollbar represents.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the units used by
+     * {@link #computeVerticalScrollExtent()} and {@link #computeVerticalScrollOffset()}.</p>
+     *
+     * <p>Default implementation returns 0.</p>
+     *
+     * <p>If you want to support scroll bars, override
+     * {@link RecyclerView.LayoutManager#computeVerticalScrollRange(RecyclerView.State)} in your
+     * LayoutManager.</p>
+     *
+     * @return The total vertical range represented by the vertical scrollbar
+     * @see RecyclerView.LayoutManager#computeVerticalScrollRange(RecyclerView.State)
+     */
+    @Override
+    public int computeVerticalScrollRange() {
+        if (mLayout == null) {
+            return 0;
+        }
+        return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollRange(mState) : 0;
+    }
+
+
+    void eatRequestLayout() {
+        mEatRequestLayout++;
+        if (mEatRequestLayout == 1 && !mLayoutFrozen) {
+            mLayoutRequestEaten = false;
+        }
+    }
+
+    void resumeRequestLayout(boolean performLayoutChildren) {
+        if (mEatRequestLayout < 1) {
+            //noinspection PointlessBooleanExpression
+            if (DEBUG) {
+                throw new IllegalStateException("invalid eat request layout count");
+            }
+            mEatRequestLayout = 1;
+        }
+        if (!performLayoutChildren) {
+            // Reset the layout request eaten counter.
+            // This is necessary since eatRequest calls can be nested in which case the other
+            // call will override the inner one.
+            // for instance:
+            // eat layout for process adapter updates
+            //   eat layout for dispatchLayout
+            //     a bunch of req layout calls arrive
+
+            mLayoutRequestEaten = false;
+        }
+        if (mEatRequestLayout == 1) {
+            // when layout is frozen we should delay dispatchLayout()
+            if (performLayoutChildren && mLayoutRequestEaten && !mLayoutFrozen
+                    && mLayout != null && mAdapter != null) {
+                dispatchLayout();
+            }
+            if (!mLayoutFrozen) {
+                mLayoutRequestEaten = false;
+            }
+        }
+        mEatRequestLayout--;
+    }
+
+    /**
+     * Enable or disable layout and scroll.  After <code>setLayoutFrozen(true)</code> is called,
+     * Layout requests will be postponed until <code>setLayoutFrozen(false)</code> is called;
+     * child views are not updated when RecyclerView is frozen, {@link #smoothScrollBy(int, int)},
+     * {@link #scrollBy(int, int)}, {@link #scrollToPosition(int)} and
+     * {@link #smoothScrollToPosition(int)} are dropped; TouchEvents and GenericMotionEvents are
+     * dropped; {@link LayoutManager#onFocusSearchFailed(View, int, Recycler, State)} will not be
+     * called.
+     *
+     * <p>
+     * <code>setLayoutFrozen(true)</code> does not prevent app from directly calling {@link
+     * LayoutManager#scrollToPosition(int)}, {@link LayoutManager#smoothScrollToPosition(
+     * RecyclerView, State, int)}.
+     * <p>
+     * {@link #setAdapter(Adapter)} and {@link #swapAdapter(Adapter, boolean)} will automatically
+     * stop frozen.
+     * <p>
+     * Note: Running ItemAnimator is not stopped automatically,  it's caller's
+     * responsibility to call ItemAnimator.end().
+     *
+     * @param frozen   true to freeze layout and scroll, false to re-enable.
+     */
+    public void setLayoutFrozen(boolean frozen) {
+        if (frozen != mLayoutFrozen) {
+            assertNotInLayoutOrScroll("Do not setLayoutFrozen in layout or scroll");
+            if (!frozen) {
+                mLayoutFrozen = false;
+                if (mLayoutRequestEaten && mLayout != null && mAdapter != null) {
+                    requestLayout();
+                }
+                mLayoutRequestEaten = false;
+            } else {
+                final long now = SystemClock.uptimeMillis();
+                MotionEvent cancelEvent = MotionEvent.obtain(now, now,
+                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+                onTouchEvent(cancelEvent);
+                mLayoutFrozen = true;
+                mIgnoreMotionEventTillDown = true;
+                stopScroll();
+            }
+        }
+    }
+
+    /**
+     * Returns true if layout and scroll are frozen.
+     *
+     * @return true if layout and scroll are frozen
+     * @see #setLayoutFrozen(boolean)
+     */
+    public boolean isLayoutFrozen() {
+        return mLayoutFrozen;
+    }
+
+    /**
+     * Animate a scroll by the given amount of pixels along either axis.
+     *
+     * @param dx Pixels to scroll horizontally
+     * @param dy Pixels to scroll vertically
+     */
+    public void smoothScrollBy(int dx, int dy) {
+        smoothScrollBy(dx, dy, null);
+    }
+
+    /**
+     * Animate a scroll by the given amount of pixels along either axis.
+     *
+     * @param dx Pixels to scroll horizontally
+     * @param dy Pixels to scroll vertically
+     * @param interpolator {@link Interpolator} to be used for scrolling. If it is
+     *                     {@code null}, RecyclerView is going to use the default interpolator.
+     */
+    public void smoothScrollBy(int dx, int dy, Interpolator interpolator) {
+        if (mLayout == null) {
+            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
+            return;
+        }
+        if (mLayoutFrozen) {
+            return;
+        }
+        if (!mLayout.canScrollHorizontally()) {
+            dx = 0;
+        }
+        if (!mLayout.canScrollVertically()) {
+            dy = 0;
+        }
+        if (dx != 0 || dy != 0) {
+            mViewFlinger.smoothScrollBy(dx, dy, interpolator);
+        }
+    }
+
+    /**
+     * Begin a standard fling with an initial velocity along each axis in pixels per second.
+     * If the velocity given is below the system-defined minimum this method will return false
+     * and no fling will occur.
+     *
+     * @param velocityX Initial horizontal velocity in pixels per second
+     * @param velocityY Initial vertical velocity in pixels per second
+     * @return true if the fling was started, false if the velocity was too low to fling or
+     * LayoutManager does not support scrolling in the axis fling is issued.
+     *
+     * @see LayoutManager#canScrollVertically()
+     * @see LayoutManager#canScrollHorizontally()
+     */
+    public boolean fling(int velocityX, int velocityY) {
+        if (mLayout == null) {
+            Log.e(TAG, "Cannot fling without a LayoutManager set. "
+                    + "Call setLayoutManager with a non-null argument.");
+            return false;
+        }
+        if (mLayoutFrozen) {
+            return false;
+        }
+
+        final boolean canScrollHorizontal = mLayout.canScrollHorizontally();
+        final boolean canScrollVertical = mLayout.canScrollVertically();
+
+        if (!canScrollHorizontal || Math.abs(velocityX) < mMinFlingVelocity) {
+            velocityX = 0;
+        }
+        if (!canScrollVertical || Math.abs(velocityY) < mMinFlingVelocity) {
+            velocityY = 0;
+        }
+        if (velocityX == 0 && velocityY == 0) {
+            // If we don't have any velocity, return false
+            return false;
+        }
+
+        if (!dispatchNestedPreFling(velocityX, velocityY)) {
+            final boolean canScroll = canScrollHorizontal || canScrollVertical;
+            dispatchNestedFling(velocityX, velocityY, canScroll);
+
+            if (mOnFlingListener != null && mOnFlingListener.onFling(velocityX, velocityY)) {
+                return true;
+            }
+
+            if (canScroll) {
+                velocityX = Math.max(-mMaxFlingVelocity, Math.min(velocityX, mMaxFlingVelocity));
+                velocityY = Math.max(-mMaxFlingVelocity, Math.min(velocityY, mMaxFlingVelocity));
+                mViewFlinger.fling(velocityX, velocityY);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Stop any current scroll in progress, such as one started by
+     * {@link #smoothScrollBy(int, int)}, {@link #fling(int, int)} or a touch-initiated fling.
+     */
+    public void stopScroll() {
+        setScrollState(SCROLL_STATE_IDLE);
+        stopScrollersInternal();
+    }
+
+    /**
+     * Similar to {@link #stopScroll()} but does not set the state.
+     */
+    private void stopScrollersInternal() {
+        mViewFlinger.stop();
+        if (mLayout != null) {
+            mLayout.stopSmoothScroller();
+        }
+    }
+
+    /**
+     * Returns the minimum velocity to start a fling.
+     *
+     * @return The minimum velocity to start a fling
+     */
+    public int getMinFlingVelocity() {
+        return mMinFlingVelocity;
+    }
+
+
+    /**
+     * Returns the maximum fling velocity used by this RecyclerView.
+     *
+     * @return The maximum fling velocity used by this RecyclerView.
+     */
+    public int getMaxFlingVelocity() {
+        return mMaxFlingVelocity;
+    }
+
+    /**
+     * Apply a pull to relevant overscroll glow effects
+     */
+    private void pullGlows(float x, float overscrollX, float y, float overscrollY) {
+        boolean invalidate = false;
+        if (overscrollX < 0) {
+            ensureLeftGlow();
+            mLeftGlow.onPull(-overscrollX / getWidth(), 1f - y  / getHeight());
+            invalidate = true;
+        } else if (overscrollX > 0) {
+            ensureRightGlow();
+            mRightGlow.onPull(overscrollX / getWidth(), y / getHeight());
+            invalidate = true;
+        }
+
+        if (overscrollY < 0) {
+            ensureTopGlow();
+            mTopGlow.onPull(-overscrollY / getHeight(), x / getWidth());
+            invalidate = true;
+        } else if (overscrollY > 0) {
+            ensureBottomGlow();
+            mBottomGlow.onPull(overscrollY / getHeight(), 1f - x / getWidth());
+            invalidate = true;
+        }
+
+        if (invalidate || overscrollX != 0 || overscrollY != 0) {
+            postInvalidateOnAnimation();
+        }
+    }
+
+    private void releaseGlows() {
+        boolean needsInvalidate = false;
+        if (mLeftGlow != null) {
+            mLeftGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (mTopGlow != null) {
+            mTopGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (mRightGlow != null) {
+            mRightGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (mBottomGlow != null) {
+            mBottomGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (needsInvalidate) {
+            postInvalidateOnAnimation();
+        }
+    }
+
+    void considerReleasingGlowsOnScroll(int dx, int dy) {
+        boolean needsInvalidate = false;
+        if (mLeftGlow != null && !mLeftGlow.isFinished() && dx > 0) {
+            mLeftGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (mRightGlow != null && !mRightGlow.isFinished() && dx < 0) {
+            mRightGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (mTopGlow != null && !mTopGlow.isFinished() && dy > 0) {
+            mTopGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (mBottomGlow != null && !mBottomGlow.isFinished() && dy < 0) {
+            mBottomGlow.onRelease();
+            needsInvalidate = true;
+        }
+        if (needsInvalidate) {
+            postInvalidateOnAnimation();
+        }
+    }
+
+    void absorbGlows(int velocityX, int velocityY) {
+        if (velocityX < 0) {
+            ensureLeftGlow();
+            mLeftGlow.onAbsorb(-velocityX);
+        } else if (velocityX > 0) {
+            ensureRightGlow();
+            mRightGlow.onAbsorb(velocityX);
+        }
+
+        if (velocityY < 0) {
+            ensureTopGlow();
+            mTopGlow.onAbsorb(-velocityY);
+        } else if (velocityY > 0) {
+            ensureBottomGlow();
+            mBottomGlow.onAbsorb(velocityY);
+        }
+
+        if (velocityX != 0 || velocityY != 0) {
+            postInvalidateOnAnimation();
+        }
+    }
+
+    void ensureLeftGlow() {
+        if (mLeftGlow != null) {
+            return;
+        }
+        mLeftGlow = new EdgeEffect(getContext());
+        if (mClipToPadding) {
+            mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
+                    getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
+        } else {
+            mLeftGlow.setSize(getMeasuredHeight(), getMeasuredWidth());
+        }
+    }
+
+    void ensureRightGlow() {
+        if (mRightGlow != null) {
+            return;
+        }
+        mRightGlow = new EdgeEffect(getContext());
+        if (mClipToPadding) {
+            mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
+                    getMeasuredWidth() - getPaddingLeft() - getPaddingRight());
+        } else {
+            mRightGlow.setSize(getMeasuredHeight(), getMeasuredWidth());
+        }
+    }
+
+    void ensureTopGlow() {
+        if (mTopGlow != null) {
+            return;
+        }
+        mTopGlow = new EdgeEffect(getContext());
+        if (mClipToPadding) {
+            mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
+                    getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
+        } else {
+            mTopGlow.setSize(getMeasuredWidth(), getMeasuredHeight());
+        }
+
+    }
+
+    void ensureBottomGlow() {
+        if (mBottomGlow != null) {
+            return;
+        }
+        mBottomGlow = new EdgeEffect(getContext());
+        if (mClipToPadding) {
+            mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
+                    getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
+        } else {
+            mBottomGlow.setSize(getMeasuredWidth(), getMeasuredHeight());
+        }
+    }
+
+    void invalidateGlows() {
+        mLeftGlow = mRightGlow = mTopGlow = mBottomGlow = null;
+    }
+
+    /**
+     * Since RecyclerView is a collection ViewGroup that includes virtual children (items that are
+     * in the Adapter but not visible in the UI), it employs a more involved focus search strategy
+     * that differs from other ViewGroups.
+     * <p>
+     * It first does a focus search within the RecyclerView. If this search finds a View that is in
+     * the focus direction with respect to the currently focused View, RecyclerView returns that
+     * child as the next focus target. When it cannot find such child, it calls
+     * {@link LayoutManager#onFocusSearchFailed(View, int, Recycler, State)} to layout more Views
+     * in the focus search direction. If LayoutManager adds a View that matches the
+     * focus search criteria, it will be returned as the focus search result. Otherwise,
+     * RecyclerView will call parent to handle the focus search like a regular ViewGroup.
+     * <p>
+     * When the direction is {@link View#FOCUS_FORWARD} or {@link View#FOCUS_BACKWARD}, a View that
+     * is not in the focus direction is still valid focus target which may not be the desired
+     * behavior if the Adapter has more children in the focus direction. To handle this case,
+     * RecyclerView converts the focus direction to an absolute direction and makes a preliminary
+     * focus search in that direction. If there are no Views to gain focus, it will call
+     * {@link LayoutManager#onFocusSearchFailed(View, int, Recycler, State)} before running a
+     * focus search with the original (relative) direction. This allows RecyclerView to provide
+     * better candidates to the focus search while still allowing the view system to take focus from
+     * the RecyclerView and give it to a more suitable child if such child exists.
+     *
+     * @param focused The view that currently has focus
+     * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+     * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, {@link View#FOCUS_FORWARD},
+     * {@link View#FOCUS_BACKWARD} or 0 for not applicable.
+     *
+     * @return A new View that can be the next focus after the focused View
+     */
+    @Override
+    public View focusSearch(View focused, int direction) {
+        View result = mLayout.onInterceptFocusSearch(focused, direction);
+        if (result != null) {
+            return result;
+        }
+        final boolean canRunFocusFailure = mAdapter != null && mLayout != null
+                && !isComputingLayout() && !mLayoutFrozen;
+
+        final FocusFinder ff = FocusFinder.getInstance();
+        if (canRunFocusFailure
+                && (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD)) {
+            // convert direction to absolute direction and see if we have a view there and if not
+            // tell LayoutManager to add if it can.
+            boolean needsFocusFailureLayout = false;
+            if (mLayout.canScrollVertically()) {
+                final int absDir =
+                        direction == View.FOCUS_FORWARD ? View.FOCUS_DOWN : View.FOCUS_UP;
+                final View found = ff.findNextFocus(this, focused, absDir);
+                needsFocusFailureLayout = found == null;
+                if (FORCE_ABS_FOCUS_SEARCH_DIRECTION) {
+                    // Workaround for broken FOCUS_BACKWARD in API 15 and older devices.
+                    direction = absDir;
+                }
+            }
+            if (!needsFocusFailureLayout && mLayout.canScrollHorizontally()) {
+                boolean rtl = mLayout.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+                final int absDir = (direction == View.FOCUS_FORWARD) ^ rtl
+                        ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+                final View found = ff.findNextFocus(this, focused, absDir);
+                needsFocusFailureLayout = found == null;
+                if (FORCE_ABS_FOCUS_SEARCH_DIRECTION) {
+                    // Workaround for broken FOCUS_BACKWARD in API 15 and older devices.
+                    direction = absDir;
+                }
+            }
+            if (needsFocusFailureLayout) {
+                consumePendingUpdateOperations();
+                final View focusedItemView = findContainingItemView(focused);
+                if (focusedItemView == null) {
+                    // panic, focused view is not a child anymore, cannot call super.
+                    return null;
+                }
+                eatRequestLayout();
+                mLayout.onFocusSearchFailed(focused, direction, mRecycler, mState);
+                resumeRequestLayout(false);
+            }
+            result = ff.findNextFocus(this, focused, direction);
+        } else {
+            result = ff.findNextFocus(this, focused, direction);
+            if (result == null && canRunFocusFailure) {
+                consumePendingUpdateOperations();
+                final View focusedItemView = findContainingItemView(focused);
+                if (focusedItemView == null) {
+                    // panic, focused view is not a child anymore, cannot call super.
+                    return null;
+                }
+                eatRequestLayout();
+                result = mLayout.onFocusSearchFailed(focused, direction, mRecycler, mState);
+                resumeRequestLayout(false);
+            }
+        }
+        return isPreferredNextFocus(focused, result, direction)
+                ? result : super.focusSearch(focused, direction);
+    }
+
+    /**
+     * Checks if the new focus candidate is a good enough candidate such that RecyclerView will
+     * assign it as the next focus View instead of letting view hierarchy decide.
+     * A good candidate means a View that is aligned in the focus direction wrt the focused View
+     * and is not the RecyclerView itself.
+     * When this method returns false, RecyclerView will let the parent make the decision so the
+     * same View may still get the focus as a result of that search.
+     */
+    private boolean isPreferredNextFocus(View focused, View next, int direction) {
+        if (next == null || next == this) {
+            return false;
+        }
+        if (focused == null) {
+            return true;
+        }
+
+        if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
+            final boolean rtl = mLayout.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+            final int absHorizontal = (direction == View.FOCUS_FORWARD) ^ rtl
+                    ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+            if (isPreferredNextFocusAbsolute(focused, next, absHorizontal)) {
+                return true;
+            }
+            if (direction == View.FOCUS_FORWARD) {
+                return isPreferredNextFocusAbsolute(focused, next, View.FOCUS_DOWN);
+            } else {
+                return isPreferredNextFocusAbsolute(focused, next, View.FOCUS_UP);
+            }
+        } else {
+            return isPreferredNextFocusAbsolute(focused, next, direction);
+        }
+
+    }
+
+    /**
+     * Logic taken from FocusSearch#isCandidate
+     */
+    private boolean isPreferredNextFocusAbsolute(View focused, View next, int direction) {
+        mTempRect.set(0, 0, focused.getWidth(), focused.getHeight());
+        mTempRect2.set(0, 0, next.getWidth(), next.getHeight());
+        offsetDescendantRectToMyCoords(focused, mTempRect);
+        offsetDescendantRectToMyCoords(next, mTempRect2);
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                return (mTempRect.right > mTempRect2.right
+                        || mTempRect.left >= mTempRect2.right)
+                        && mTempRect.left > mTempRect2.left;
+            case View.FOCUS_RIGHT:
+                return (mTempRect.left < mTempRect2.left
+                        || mTempRect.right <= mTempRect2.left)
+                        && mTempRect.right < mTempRect2.right;
+            case View.FOCUS_UP:
+                return (mTempRect.bottom > mTempRect2.bottom
+                        || mTempRect.top >= mTempRect2.bottom)
+                        && mTempRect.top > mTempRect2.top;
+            case View.FOCUS_DOWN:
+                return (mTempRect.top < mTempRect2.top
+                        || mTempRect.bottom <= mTempRect2.top)
+                        && mTempRect.bottom < mTempRect2.bottom;
+        }
+        throw new IllegalArgumentException("direction must be absolute. received:" + direction);
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        if (!mLayout.onRequestChildFocus(this, mState, child, focused) && focused != null) {
+            mTempRect.set(0, 0, focused.getWidth(), focused.getHeight());
+
+            // get item decor offsets w/o refreshing. If they are invalid, there will be another
+            // layout pass to fix them, then it is LayoutManager's responsibility to keep focused
+            // View in viewport.
+            final ViewGroup.LayoutParams focusedLayoutParams = focused.getLayoutParams();
+            if (focusedLayoutParams instanceof LayoutParams) {
+                // if focused child has item decors, use them. Otherwise, ignore.
+                final LayoutParams lp = (LayoutParams) focusedLayoutParams;
+                if (!lp.mInsetsDirty) {
+                    final Rect insets = lp.mDecorInsets;
+                    mTempRect.left -= insets.left;
+                    mTempRect.right += insets.right;
+                    mTempRect.top -= insets.top;
+                    mTempRect.bottom += insets.bottom;
+                }
+            }
+
+            offsetDescendantRectToMyCoords(focused, mTempRect);
+            offsetRectIntoDescendantCoords(child, mTempRect);
+            requestChildRectangleOnScreen(child, mTempRect, !mFirstLayoutComplete);
+        }
+        super.requestChildFocus(child, focused);
+    }
+
+    @Override
+    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
+        return mLayout.requestChildRectangleOnScreen(this, child, rect, immediate);
+    }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        if (mLayout == null || !mLayout.onAddFocusables(this, views, direction, focusableMode)) {
+            super.addFocusables(views, direction, focusableMode);
+        }
+    }
+
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        if (isComputingLayout()) {
+            // if we are in the middle of a layout calculation, don't let any child take focus.
+            // RV will handle it after layout calculation is finished.
+            return false;
+        }
+        return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mLayoutOrScrollCounter = 0;
+        mIsAttached = true;
+        mFirstLayoutComplete = mFirstLayoutComplete && !isLayoutRequested();
+        if (mLayout != null) {
+            mLayout.dispatchAttachedToWindow(this);
+        }
+        mPostedAnimatorRunner = false;
+
+        if (ALLOW_THREAD_GAP_WORK) {
+            // Register with gap worker
+            mGapWorker = GapWorker.sGapWorker.get();
+            if (mGapWorker == null) {
+                mGapWorker = new GapWorker();
+
+                // break 60 fps assumption if data from display appears valid
+                // NOTE: we only do this query once, statically, because it's very expensive (> 1ms)
+                Display display = getDisplay();
+                float refreshRate = 60.0f;
+                if (!isInEditMode() && display != null) {
+                    float displayRefreshRate = display.getRefreshRate();
+                    if (displayRefreshRate >= 30.0f) {
+                        refreshRate = displayRefreshRate;
+                    }
+                }
+                mGapWorker.mFrameIntervalNs = (long) (1000000000 / refreshRate);
+                GapWorker.sGapWorker.set(mGapWorker);
+            }
+            mGapWorker.add(this);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mItemAnimator != null) {
+            mItemAnimator.endAnimations();
+        }
+        stopScroll();
+        mIsAttached = false;
+        if (mLayout != null) {
+            mLayout.dispatchDetachedFromWindow(this, mRecycler);
+        }
+        mPendingAccessibilityImportanceChange.clear();
+        removeCallbacks(mItemAnimatorRunner);
+        mViewInfoStore.onDetach();
+
+        if (ALLOW_THREAD_GAP_WORK) {
+            // Unregister with gap worker
+            mGapWorker.remove(this);
+            mGapWorker = null;
+        }
+    }
+
+    /**
+     * Returns true if RecyclerView is attached to window.
+     */
+    // @override
+    public boolean isAttachedToWindow() {
+        return mIsAttached;
+    }
+
+    /**
+     * Checks if RecyclerView is in the middle of a layout or scroll and throws an
+     * {@link IllegalStateException} if it <b>is not</b>.
+     *
+     * @param message The message for the exception. Can be null.
+     * @see #assertNotInLayoutOrScroll(String)
+     */
+    void assertInLayoutOrScroll(String message) {
+        if (!isComputingLayout()) {
+            if (message == null) {
+                throw new IllegalStateException("Cannot call this method unless RecyclerView is "
+                        + "computing a layout or scrolling");
+            }
+            throw new IllegalStateException(message);
+
+        }
+    }
+
+    /**
+     * Checks if RecyclerView is in the middle of a layout or scroll and throws an
+     * {@link IllegalStateException} if it <b>is</b>.
+     *
+     * @param message The message for the exception. Can be null.
+     * @see #assertInLayoutOrScroll(String)
+     */
+    void assertNotInLayoutOrScroll(String message) {
+        if (isComputingLayout()) {
+            if (message == null) {
+                throw new IllegalStateException("Cannot call this method while RecyclerView is "
+                        + "computing a layout or scrolling");
+            }
+            throw new IllegalStateException(message);
+        }
+        if (mDispatchScrollCounter > 0) {
+            Log.w(TAG, "Cannot call this method in a scroll callback. Scroll callbacks might be run"
+                    + " during a measure & layout pass where you cannot change the RecyclerView"
+                    + " data. Any method call that might change the structure of the RecyclerView"
+                    + " or the adapter contents should be postponed to the next frame.",
+                    new IllegalStateException(""));
+        }
+    }
+
+    /**
+     * Add an {@link OnItemTouchListener} to intercept touch events before they are dispatched
+     * to child views or this view's standard scrolling behavior.
+     *
+     * <p>Client code may use listeners to implement item manipulation behavior. Once a listener
+     * returns true from
+     * {@link OnItemTouchListener#onInterceptTouchEvent(RecyclerView, MotionEvent)} its
+     * {@link OnItemTouchListener#onTouchEvent(RecyclerView, MotionEvent)} method will be called
+     * for each incoming MotionEvent until the end of the gesture.</p>
+     *
+     * @param listener Listener to add
+     * @see SimpleOnItemTouchListener
+     */
+    public void addOnItemTouchListener(OnItemTouchListener listener) {
+        mOnItemTouchListeners.add(listener);
+    }
+
+    /**
+     * Remove an {@link OnItemTouchListener}. It will no longer be able to intercept touch events.
+     *
+     * @param listener Listener to remove
+     */
+    public void removeOnItemTouchListener(OnItemTouchListener listener) {
+        mOnItemTouchListeners.remove(listener);
+        if (mActiveOnItemTouchListener == listener) {
+            mActiveOnItemTouchListener = null;
+        }
+    }
+
+    private boolean dispatchOnItemTouchIntercept(MotionEvent e) {
+        final int action = e.getAction();
+        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_DOWN) {
+            mActiveOnItemTouchListener = null;
+        }
+
+        final int listenerCount = mOnItemTouchListeners.size();
+        for (int i = 0; i < listenerCount; i++) {
+            final OnItemTouchListener listener = mOnItemTouchListeners.get(i);
+            if (listener.onInterceptTouchEvent(this, e) && action != MotionEvent.ACTION_CANCEL) {
+                mActiveOnItemTouchListener = listener;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean dispatchOnItemTouch(MotionEvent e) {
+        final int action = e.getAction();
+        if (mActiveOnItemTouchListener != null) {
+            if (action == MotionEvent.ACTION_DOWN) {
+                // Stale state from a previous gesture, we're starting a new one. Clear it.
+                mActiveOnItemTouchListener = null;
+            } else {
+                mActiveOnItemTouchListener.onTouchEvent(this, e);
+                if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+                    // Clean up for the next gesture.
+                    mActiveOnItemTouchListener = null;
+                }
+                return true;
+            }
+        }
+
+        // Listeners will have already received the ACTION_DOWN via dispatchOnItemTouchIntercept
+        // as called from onInterceptTouchEvent; skip it.
+        if (action != MotionEvent.ACTION_DOWN) {
+            final int listenerCount = mOnItemTouchListeners.size();
+            for (int i = 0; i < listenerCount; i++) {
+                final OnItemTouchListener listener = mOnItemTouchListeners.get(i);
+                if (listener.onInterceptTouchEvent(this, e)) {
+                    mActiveOnItemTouchListener = listener;
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent e) {
+        if (mLayoutFrozen) {
+            // When layout is frozen,  RV does not intercept the motion event.
+            // A child view e.g. a button may still get the click.
+            return false;
+        }
+        if (dispatchOnItemTouchIntercept(e)) {
+            cancelTouch();
+            return true;
+        }
+
+        if (mLayout == null) {
+            return false;
+        }
+
+        final boolean canScrollHorizontally = mLayout.canScrollHorizontally();
+        final boolean canScrollVertically = mLayout.canScrollVertically();
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(e);
+
+        final int action = e.getActionMasked();
+        final int actionIndex = e.getActionIndex();
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                if (mIgnoreMotionEventTillDown) {
+                    mIgnoreMotionEventTillDown = false;
+                }
+                mScrollPointerId = e.getPointerId(0);
+                mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f);
+                mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);
+
+                if (mScrollState == SCROLL_STATE_SETTLING) {
+                    getParent().requestDisallowInterceptTouchEvent(true);
+                    setScrollState(SCROLL_STATE_DRAGGING);
+                }
+
+                // Clear the nested offsets
+                mNestedOffsets[0] = mNestedOffsets[1] = 0;
+
+                int nestedScrollAxis = View.SCROLL_AXIS_NONE;
+                if (canScrollHorizontally) {
+                    nestedScrollAxis |= View.SCROLL_AXIS_HORIZONTAL;
+                }
+                if (canScrollVertically) {
+                    nestedScrollAxis |= View.SCROLL_AXIS_VERTICAL;
+                }
+                startNestedScroll(nestedScrollAxis);
+                break;
+
+            case MotionEvent.ACTION_POINTER_DOWN:
+                mScrollPointerId = e.getPointerId(actionIndex);
+                mInitialTouchX = mLastTouchX = (int) (e.getX(actionIndex) + 0.5f);
+                mInitialTouchY = mLastTouchY = (int) (e.getY(actionIndex) + 0.5f);
+                break;
+
+            case MotionEvent.ACTION_MOVE: {
+                final int index = e.findPointerIndex(mScrollPointerId);
+                if (index < 0) {
+                    Log.e(TAG, "Error processing scroll; pointer index for id "
+                            + mScrollPointerId + " not found. Did any MotionEvents get skipped?");
+                    return false;
+                }
+
+                final int x = (int) (e.getX(index) + 0.5f);
+                final int y = (int) (e.getY(index) + 0.5f);
+                if (mScrollState != SCROLL_STATE_DRAGGING) {
+                    final int dx = x - mInitialTouchX;
+                    final int dy = y - mInitialTouchY;
+                    boolean startScroll = false;
+                    if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {
+                        mLastTouchX = mInitialTouchX + mTouchSlop * (dx < 0 ? -1 : 1);
+                        startScroll = true;
+                    }
+                    if (canScrollVertically && Math.abs(dy) > mTouchSlop) {
+                        mLastTouchY = mInitialTouchY + mTouchSlop * (dy < 0 ? -1 : 1);
+                        startScroll = true;
+                    }
+                    if (startScroll) {
+                        setScrollState(SCROLL_STATE_DRAGGING);
+                    }
+                }
+            } break;
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                onPointerUp(e);
+            } break;
+
+            case MotionEvent.ACTION_UP: {
+                mVelocityTracker.clear();
+                stopNestedScroll();
+            } break;
+
+            case MotionEvent.ACTION_CANCEL: {
+                cancelTouch();
+            }
+        }
+        return mScrollState == SCROLL_STATE_DRAGGING;
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        final int listenerCount = mOnItemTouchListeners.size();
+        for (int i = 0; i < listenerCount; i++) {
+            final OnItemTouchListener listener = mOnItemTouchListeners.get(i);
+            listener.onRequestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent e) {
+        if (mLayoutFrozen || mIgnoreMotionEventTillDown) {
+            return false;
+        }
+        if (dispatchOnItemTouch(e)) {
+            cancelTouch();
+            return true;
+        }
+
+        if (mLayout == null) {
+            return false;
+        }
+
+        final boolean canScrollHorizontally = mLayout.canScrollHorizontally();
+        final boolean canScrollVertically = mLayout.canScrollVertically();
+
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        boolean eventAddedToVelocityTracker = false;
+
+        final MotionEvent vtev = MotionEvent.obtain(e);
+        final int action = e.getActionMasked();
+        final int actionIndex = e.getActionIndex();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mNestedOffsets[0] = mNestedOffsets[1] = 0;
+        }
+        vtev.offsetLocation(mNestedOffsets[0], mNestedOffsets[1]);
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                mScrollPointerId = e.getPointerId(0);
+                mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f);
+                mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f);
+
+                int nestedScrollAxis = View.SCROLL_AXIS_NONE;
+                if (canScrollHorizontally) {
+                    nestedScrollAxis |= View.SCROLL_AXIS_HORIZONTAL;
+                }
+                if (canScrollVertically) {
+                    nestedScrollAxis |= View.SCROLL_AXIS_VERTICAL;
+                }
+                startNestedScroll(nestedScrollAxis);
+            } break;
+
+            case MotionEvent.ACTION_POINTER_DOWN: {
+                mScrollPointerId = e.getPointerId(actionIndex);
+                mInitialTouchX = mLastTouchX = (int) (e.getX(actionIndex) + 0.5f);
+                mInitialTouchY = mLastTouchY = (int) (e.getY(actionIndex) + 0.5f);
+            } break;
+
+            case MotionEvent.ACTION_MOVE: {
+                final int index = e.findPointerIndex(mScrollPointerId);
+                if (index < 0) {
+                    Log.e(TAG, "Error processing scroll; pointer index for id "
+                            + mScrollPointerId + " not found. Did any MotionEvents get skipped?");
+                    return false;
+                }
+
+                final int x = (int) (e.getX(index) + 0.5f);
+                final int y = (int) (e.getY(index) + 0.5f);
+                int dx = mLastTouchX - x;
+                int dy = mLastTouchY - y;
+
+                if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) {
+                    dx -= mScrollConsumed[0];
+                    dy -= mScrollConsumed[1];
+                    vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]);
+                    // Updated the nested offsets
+                    mNestedOffsets[0] += mScrollOffset[0];
+                    mNestedOffsets[1] += mScrollOffset[1];
+                }
+
+                if (mScrollState != SCROLL_STATE_DRAGGING) {
+                    boolean startScroll = false;
+                    if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {
+                        if (dx > 0) {
+                            dx -= mTouchSlop;
+                        } else {
+                            dx += mTouchSlop;
+                        }
+                        startScroll = true;
+                    }
+                    if (canScrollVertically && Math.abs(dy) > mTouchSlop) {
+                        if (dy > 0) {
+                            dy -= mTouchSlop;
+                        } else {
+                            dy += mTouchSlop;
+                        }
+                        startScroll = true;
+                    }
+                    if (startScroll) {
+                        setScrollState(SCROLL_STATE_DRAGGING);
+                    }
+                }
+
+                if (mScrollState == SCROLL_STATE_DRAGGING) {
+                    mLastTouchX = x - mScrollOffset[0];
+                    mLastTouchY = y - mScrollOffset[1];
+
+                    if (scrollByInternal(
+                            canScrollHorizontally ? dx : 0,
+                            canScrollVertically ? dy : 0,
+                            vtev)) {
+                        getParent().requestDisallowInterceptTouchEvent(true);
+                    }
+                    if (mGapWorker != null && (dx != 0 || dy != 0)) {
+                        mGapWorker.postFromTraversal(this, dx, dy);
+                    }
+                }
+            } break;
+
+            case MotionEvent.ACTION_POINTER_UP: {
+                onPointerUp(e);
+            } break;
+
+            case MotionEvent.ACTION_UP: {
+                mVelocityTracker.addMovement(vtev);
+                eventAddedToVelocityTracker = true;
+                mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);
+                final float xvel = canScrollHorizontally
+                        ? -mVelocityTracker.getXVelocity(mScrollPointerId) : 0;
+                final float yvel = canScrollVertically
+                        ? -mVelocityTracker.getYVelocity(mScrollPointerId) : 0;
+                if (!((xvel != 0 || yvel != 0) && fling((int) xvel, (int) yvel))) {
+                    setScrollState(SCROLL_STATE_IDLE);
+                }
+                resetTouch();
+            } break;
+
+            case MotionEvent.ACTION_CANCEL: {
+                cancelTouch();
+            } break;
+        }
+
+        if (!eventAddedToVelocityTracker) {
+            mVelocityTracker.addMovement(vtev);
+        }
+        vtev.recycle();
+
+        return true;
+    }
+
+    private void resetTouch() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.clear();
+        }
+        stopNestedScroll();
+        releaseGlows();
+    }
+
+    private void cancelTouch() {
+        resetTouch();
+        setScrollState(SCROLL_STATE_IDLE);
+    }
+
+    private void onPointerUp(MotionEvent e) {
+        final int actionIndex = e.getActionIndex();
+        if (e.getPointerId(actionIndex) == mScrollPointerId) {
+            // Pick a new pointer to pick up the slack.
+            final int newIndex = actionIndex == 0 ? 1 : 0;
+            mScrollPointerId = e.getPointerId(newIndex);
+            mInitialTouchX = mLastTouchX = (int) (e.getX(newIndex) + 0.5f);
+            mInitialTouchY = mLastTouchY = (int) (e.getY(newIndex) + 0.5f);
+        }
+    }
+
+    // @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        if (mLayout == null) {
+            return false;
+        }
+        if (mLayoutFrozen) {
+            return false;
+        }
+        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+            if (event.getAction() == MotionEvent.ACTION_SCROLL) {
+                final float vScroll, hScroll;
+                if (mLayout.canScrollVertically()) {
+                    // Inverse the sign of the vertical scroll to align the scroll orientation
+                    // with AbsListView.
+                    vScroll = -event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+                } else {
+                    vScroll = 0f;
+                }
+                if (mLayout.canScrollHorizontally()) {
+                    hScroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+                } else {
+                    hScroll = 0f;
+                }
+
+                if (vScroll != 0 || hScroll != 0) {
+                    final float scrollFactor = getScrollFactor();
+                    scrollByInternal((int) (hScroll * scrollFactor),
+                            (int) (vScroll * scrollFactor), event);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Ported from View.getVerticalScrollFactor.
+     */
+    private float getScrollFactor() {
+        if (mScrollFactor == Float.MIN_VALUE) {
+            TypedValue outValue = new TypedValue();
+            if (getContext().getTheme().resolveAttribute(
+                    android.R.attr.listPreferredItemHeight, outValue, true)) {
+                mScrollFactor = outValue.getDimension(
+                        getContext().getResources().getDisplayMetrics());
+            } else {
+                return 0; //listPreferredItemHeight is not defined, no generic scrolling
+            }
+        }
+        return mScrollFactor;
+    }
+
+    @Override
+    protected void onMeasure(int widthSpec, int heightSpec) {
+        if (mLayout == null) {
+            defaultOnMeasure(widthSpec, heightSpec);
+            return;
+        }
+        if (mLayout.mAutoMeasure) {
+            final int widthMode = MeasureSpec.getMode(widthSpec);
+            final int heightMode = MeasureSpec.getMode(heightSpec);
+            final boolean skipMeasure = widthMode == MeasureSpec.EXACTLY
+                    && heightMode == MeasureSpec.EXACTLY;
+            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
+            if (skipMeasure || mAdapter == null) {
+                return;
+            }
+            if (mState.mLayoutStep == State.STEP_START) {
+                dispatchLayoutStep1();
+            }
+            // set dimensions in 2nd step. Pre-layout should happen with old dimensions for
+            // consistency
+            mLayout.setMeasureSpecs(widthSpec, heightSpec);
+            mState.mIsMeasuring = true;
+            dispatchLayoutStep2();
+
+            // now we can get the width and height from the children.
+            mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
+
+            // if RecyclerView has non-exact width and height and if there is at least one child
+            // which also has non-exact width & height, we have to re-measure.
+            if (mLayout.shouldMeasureTwice()) {
+                mLayout.setMeasureSpecs(
+                        MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
+                mState.mIsMeasuring = true;
+                dispatchLayoutStep2();
+                // now we can get the width and height from the children.
+                mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
+            }
+        } else {
+            if (mHasFixedSize) {
+                mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
+                return;
+            }
+            // custom onMeasure
+            if (mAdapterUpdateDuringMeasure) {
+                eatRequestLayout();
+                onEnterLayoutOrScroll();
+                processAdapterUpdatesAndSetAnimationFlags();
+                onExitLayoutOrScroll();
+
+                if (mState.mRunPredictiveAnimations) {
+                    mState.mInPreLayout = true;
+                } else {
+                    // consume remaining updates to provide a consistent state with the layout pass.
+                    mAdapterHelper.consumeUpdatesInOnePass();
+                    mState.mInPreLayout = false;
+                }
+                mAdapterUpdateDuringMeasure = false;
+                resumeRequestLayout(false);
+            }
+
+            if (mAdapter != null) {
+                mState.mItemCount = mAdapter.getItemCount();
+            } else {
+                mState.mItemCount = 0;
+            }
+            eatRequestLayout();
+            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
+            resumeRequestLayout(false);
+            mState.mInPreLayout = false; // clear
+        }
+    }
+
+    /**
+     * Used when onMeasure is called before layout manager is set
+     */
+    void defaultOnMeasure(int widthSpec, int heightSpec) {
+        // calling LayoutManager here is not pretty but that API is already public and it is better
+        // than creating another method since this is internal.
+        final int width = LayoutManager.chooseSize(widthSpec,
+                getPaddingLeft() + getPaddingRight(),
+                getMinimumWidth());
+        final int height = LayoutManager.chooseSize(heightSpec,
+                getPaddingTop() + getPaddingBottom(),
+                getMinimumHeight());
+
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (w != oldw || h != oldh) {
+            invalidateGlows();
+            // layout's w/h are updated during measure/layout steps.
+        }
+    }
+
+    /**
+     * Sets the {@link ItemAnimator} that will handle animations involving changes
+     * to the items in this RecyclerView. By default, RecyclerView instantiates and
+     * uses an instance of {@link DefaultItemAnimator}. Whether item animations are
+     * enabled for the RecyclerView depends on the ItemAnimator and whether
+     * the LayoutManager {@link LayoutManager#supportsPredictiveItemAnimations()
+     * supports item animations}.
+     *
+     * @param animator The ItemAnimator being set. If null, no animations will occur
+     * when changes occur to the items in this RecyclerView.
+     */
+    public void setItemAnimator(ItemAnimator animator) {
+        if (mItemAnimator != null) {
+            mItemAnimator.endAnimations();
+            mItemAnimator.setListener(null);
+        }
+        mItemAnimator = animator;
+        if (mItemAnimator != null) {
+            mItemAnimator.setListener(mItemAnimatorListener);
+        }
+    }
+
+    void onEnterLayoutOrScroll() {
+        mLayoutOrScrollCounter++;
+    }
+
+    void onExitLayoutOrScroll() {
+        mLayoutOrScrollCounter--;
+        if (mLayoutOrScrollCounter < 1) {
+            if (DEBUG && mLayoutOrScrollCounter < 0) {
+                throw new IllegalStateException("layout or scroll counter cannot go below zero."
+                        + "Some calls are not matching");
+            }
+            mLayoutOrScrollCounter = 0;
+            dispatchContentChangedIfNecessary();
+            dispatchPendingImportantForAccessibilityChanges();
+        }
+    }
+
+    boolean isAccessibilityEnabled() {
+        return mAccessibilityManager != null && mAccessibilityManager.isEnabled();
+    }
+
+    private void dispatchContentChangedIfNecessary() {
+        final int flags = mEatenAccessibilityChangeFlags;
+        mEatenAccessibilityChangeFlags = 0;
+        if (flags != 0 && isAccessibilityEnabled()) {
+            final AccessibilityEvent event = AccessibilityEvent.obtain();
+            event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+            event.setContentChangeTypes(flags);
+            sendAccessibilityEventUnchecked(event);
+        }
+    }
+
+    /**
+     * Returns whether RecyclerView is currently computing a layout.
+     * <p>
+     * If this method returns true, it means that RecyclerView is in a lockdown state and any
+     * attempt to update adapter contents will result in an exception because adapter contents
+     * cannot be changed while RecyclerView is trying to compute the layout.
+     * <p>
+     * It is very unlikely that your code will be running during this state as it is
+     * called by the framework when a layout traversal happens or RecyclerView starts to scroll
+     * in response to system events (touch, accessibility etc).
+     * <p>
+     * This case may happen if you have some custom logic to change adapter contents in
+     * response to a View callback (e.g. focus change callback) which might be triggered during a
+     * layout calculation. In these cases, you should just postpone the change using a Handler or a
+     * similar mechanism.
+     *
+     * @return <code>true</code> if RecyclerView is currently computing a layout, <code>false</code>
+     *         otherwise
+     */
+    public boolean isComputingLayout() {
+        return mLayoutOrScrollCounter > 0;
+    }
+
+    /**
+     * Returns true if an accessibility event should not be dispatched now. This happens when an
+     * accessibility request arrives while RecyclerView does not have a stable state which is very
+     * hard to handle for a LayoutManager. Instead, this method records necessary information about
+     * the event and dispatches a window change event after the critical section is finished.
+     *
+     * @return True if the accessibility event should be postponed.
+     */
+    boolean shouldDeferAccessibilityEvent(AccessibilityEvent event) {
+        if (isComputingLayout()) {
+            int type = 0;
+            if (event != null) {
+                type = event.getContentChangeTypes();
+            }
+            if (type == 0) {
+                type = AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
+            }
+            mEatenAccessibilityChangeFlags |= type;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+        if (shouldDeferAccessibilityEvent(event)) {
+            return;
+        }
+        super.sendAccessibilityEventUnchecked(event);
+    }
+
+    /**
+     * Gets the current ItemAnimator for this RecyclerView. A null return value
+     * indicates that there is no animator and that item changes will happen without
+     * any animations. By default, RecyclerView instantiates and
+     * uses an instance of {@link DefaultItemAnimator}.
+     *
+     * @return ItemAnimator The current ItemAnimator. If null, no animations will occur
+     * when changes occur to the items in this RecyclerView.
+     */
+    public ItemAnimator getItemAnimator() {
+        return mItemAnimator;
+    }
+
+    /**
+     * Post a runnable to the next frame to run pending item animations. Only the first such
+     * request will be posted, governed by the mPostedAnimatorRunner flag.
+     */
+    void postAnimationRunner() {
+        if (!mPostedAnimatorRunner && mIsAttached) {
+            postOnAnimation(mItemAnimatorRunner);
+            mPostedAnimatorRunner = true;
+        }
+    }
+
+    private boolean predictiveItemAnimationsEnabled() {
+        return (mItemAnimator != null && mLayout.supportsPredictiveItemAnimations());
+    }
+
+    /**
+     * Consumes adapter updates and calculates which type of animations we want to run.
+     * Called in onMeasure and dispatchLayout.
+     * <p>
+     * This method may process only the pre-layout state of updates or all of them.
+     */
+    private void processAdapterUpdatesAndSetAnimationFlags() {
+        if (mDataSetHasChangedAfterLayout) {
+            // Processing these items have no value since data set changed unexpectedly.
+            // Instead, we just reset it.
+            mAdapterHelper.reset();
+            mLayout.onItemsChanged(this);
+        }
+        // simple animations are a subset of advanced animations (which will cause a
+        // pre-layout step)
+        // If layout supports predictive animations, pre-process to decide if we want to run them
+        if (predictiveItemAnimationsEnabled()) {
+            mAdapterHelper.preProcess();
+        } else {
+            mAdapterHelper.consumeUpdatesInOnePass();
+        }
+        boolean animationTypeSupported = mItemsAddedOrRemoved || mItemsChanged;
+        mState.mRunSimpleAnimations = mFirstLayoutComplete
+                && mItemAnimator != null
+                && (mDataSetHasChangedAfterLayout
+                        || animationTypeSupported
+                        || mLayout.mRequestedSimpleAnimations)
+                && (!mDataSetHasChangedAfterLayout
+                        || mAdapter.hasStableIds());
+        mState.mRunPredictiveAnimations = mState.mRunSimpleAnimations
+                && animationTypeSupported
+                && !mDataSetHasChangedAfterLayout
+                && predictiveItemAnimationsEnabled();
+    }
+
+    /**
+     * Wrapper around layoutChildren() that handles animating changes caused by layout.
+     * Animations work on the assumption that there are five different kinds of items
+     * in play:
+     * PERSISTENT: items are visible before and after layout
+     * REMOVED: items were visible before layout and were removed by the app
+     * ADDED: items did not exist before layout and were added by the app
+     * DISAPPEARING: items exist in the data set before/after, but changed from
+     * visible to non-visible in the process of layout (they were moved off
+     * screen as a side-effect of other changes)
+     * APPEARING: items exist in the data set before/after, but changed from
+     * non-visible to visible in the process of layout (they were moved on
+     * screen as a side-effect of other changes)
+     * The overall approach figures out what items exist before/after layout and
+     * infers one of the five above states for each of the items. Then the animations
+     * are set up accordingly:
+     * PERSISTENT views are animated via
+     * {@link ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+     * DISAPPEARING views are animated via
+     * {@link ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+     * APPEARING views are animated via
+     * {@link ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)}
+     * and changed views are animated via
+     * {@link ItemAnimator#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)}.
+     */
+    void dispatchLayout() {
+        if (mAdapter == null) {
+            Log.e(TAG, "No adapter attached; skipping layout");
+            // leave the state in START
+            return;
+        }
+        if (mLayout == null) {
+            Log.e(TAG, "No layout manager attached; skipping layout");
+            // leave the state in START
+            return;
+        }
+        mState.mIsMeasuring = false;
+        if (mState.mLayoutStep == State.STEP_START) {
+            dispatchLayoutStep1();
+            mLayout.setExactMeasureSpecsFrom(this);
+            dispatchLayoutStep2();
+        } else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()
+                || mLayout.getHeight() != getHeight()) {
+            // First 2 steps are done in onMeasure but looks like we have to run again due to
+            // changed size.
+            mLayout.setExactMeasureSpecsFrom(this);
+            dispatchLayoutStep2();
+        } else {
+            // always make sure we sync them (to ensure mode is exact)
+            mLayout.setExactMeasureSpecsFrom(this);
+        }
+        dispatchLayoutStep3();
+    }
+
+    private void saveFocusInfo() {
+        View child = null;
+        if (mPreserveFocusAfterLayout && hasFocus() && mAdapter != null) {
+            child = getFocusedChild();
+        }
+
+        final ViewHolder focusedVh = child == null ? null : findContainingViewHolder(child);
+        if (focusedVh == null) {
+            resetFocusInfo();
+        } else {
+            mState.mFocusedItemId = mAdapter.hasStableIds() ? focusedVh.getItemId() : NO_ID;
+            // mFocusedItemPosition should hold the current adapter position of the previously
+            // focused item. If the item is removed, we store the previous adapter position of the
+            // removed item.
+            mState.mFocusedItemPosition = mDataSetHasChangedAfterLayout ? NO_POSITION
+                    : (focusedVh.isRemoved() ? focusedVh.mOldPosition
+                            : focusedVh.getAdapterPosition());
+            mState.mFocusedSubChildId = getDeepestFocusedViewWithId(focusedVh.itemView);
+        }
+    }
+
+    private void resetFocusInfo() {
+        mState.mFocusedItemId = NO_ID;
+        mState.mFocusedItemPosition = NO_POSITION;
+        mState.mFocusedSubChildId = View.NO_ID;
+    }
+
+    /**
+     * Finds the best view candidate to request focus on using mFocusedItemPosition index of the
+     * previously focused item. It first traverses the adapter forward to find a focusable candidate
+     * and if no such candidate is found, it reverses the focus search direction for the items
+     * before the mFocusedItemPosition'th index;
+     * @return The best candidate to request focus on, or null if no such candidate exists. Null
+     * indicates all the existing adapter items are unfocusable.
+     */
+    @Nullable
+    private View findNextViewToFocus() {
+        int startFocusSearchIndex = mState.mFocusedItemPosition != -1 ? mState.mFocusedItemPosition
+                : 0;
+        ViewHolder nextFocus;
+        final int itemCount = mState.getItemCount();
+        for (int i = startFocusSearchIndex; i < itemCount; i++) {
+            nextFocus = findViewHolderForAdapterPosition(i);
+            if (nextFocus == null) {
+                break;
+            }
+            if (nextFocus.itemView.hasFocusable()) {
+                return nextFocus.itemView;
+            }
+        }
+        final int limit = Math.min(itemCount, startFocusSearchIndex);
+        for (int i = limit - 1; i >= 0; i--) {
+            nextFocus = findViewHolderForAdapterPosition(i);
+            if (nextFocus == null) {
+                return null;
+            }
+            if (nextFocus.itemView.hasFocusable()) {
+                return nextFocus.itemView;
+            }
+        }
+        return null;
+    }
+
+    private void recoverFocusFromState() {
+        if (!mPreserveFocusAfterLayout || mAdapter == null || !hasFocus()
+                || getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS
+                || (getDescendantFocusability() == FOCUS_BEFORE_DESCENDANTS && isFocused())) {
+            // No-op if either of these cases happens:
+            // 1. RV has no focus, or 2. RV blocks focus to its children, or 3. RV takes focus
+            // before its children and is focused (i.e. it already stole the focus away from its
+            // descendants).
+            return;
+        }
+        // only recover focus if RV itself has the focus or the focused view is hidden
+        if (!isFocused()) {
+            final View focusedChild = getFocusedChild();
+            if (IGNORE_DETACHED_FOCUSED_CHILD
+                    && (focusedChild.getParent() == null || !focusedChild.hasFocus())) {
+                // Special handling of API 15-. A focused child can be invalid because mFocus is not
+                // cleared when the child is detached (mParent = null),
+                // This happens because clearFocus on API 15- does not invalidate mFocus of its
+                // parent when this child is detached.
+                // For API 16+, this is not an issue because requestFocus takes care of clearing the
+                // prior detached focused child. For API 15- the problem happens in 2 cases because
+                // clearChild does not call clearChildFocus on RV: 1. setFocusable(false) is called
+                // for the current focused item which calls clearChild or 2. when the prior focused
+                // child is removed, removeDetachedView called in layout step 3 which calls
+                // clearChild. We should ignore this invalid focused child in all our calculations
+                // for the next view to receive focus, and apply the focus recovery logic instead.
+                if (mChildHelper.getChildCount() == 0) {
+                    // No children left. Request focus on the RV itself since one of its children
+                    // was holding focus previously.
+                    requestFocus();
+                    return;
+                }
+            } else if (!mChildHelper.isHidden(focusedChild)) {
+                // If the currently focused child is hidden, apply the focus recovery logic.
+                // Otherwise return, i.e. the currently (unhidden) focused child is good enough :/.
+                return;
+            }
+        }
+        ViewHolder focusTarget = null;
+        // RV first attempts to locate the previously focused item to request focus on using
+        // mFocusedItemId. If such an item no longer exists, it then makes a best-effort attempt to
+        // find the next best candidate to request focus on based on mFocusedItemPosition.
+        if (mState.mFocusedItemId != NO_ID && mAdapter.hasStableIds()) {
+            focusTarget = findViewHolderForItemId(mState.mFocusedItemId);
+        }
+        View viewToFocus = null;
+        if (focusTarget == null || mChildHelper.isHidden(focusTarget.itemView)
+                || !focusTarget.itemView.hasFocusable()) {
+            if (mChildHelper.getChildCount() > 0) {
+                // At this point, RV has focus and either of these conditions are true:
+                // 1. There's no previously focused item either because RV received focused before
+                // layout, or the previously focused item was removed, or RV doesn't have stable IDs
+                // 2. Previous focus child is hidden, or 3. Previous focused child is no longer
+                // focusable. In either of these cases, we make sure that RV still passes down the
+                // focus to one of its focusable children using a best-effort algorithm.
+                viewToFocus = findNextViewToFocus();
+            }
+        } else {
+            // looks like the focused item has been replaced with another view that represents the
+            // same item in the adapter. Request focus on that.
+            viewToFocus = focusTarget.itemView;
+        }
+
+        if (viewToFocus != null) {
+            if (mState.mFocusedSubChildId != NO_ID) {
+                View child = viewToFocus.findViewById(mState.mFocusedSubChildId);
+                if (child != null && child.isFocusable()) {
+                    viewToFocus = child;
+                }
+            }
+            viewToFocus.requestFocus();
+        }
+    }
+
+    private int getDeepestFocusedViewWithId(View view) {
+        int lastKnownId = view.getId();
+        while (!view.isFocused() && view instanceof ViewGroup && view.hasFocus()) {
+            view = ((ViewGroup) view).getFocusedChild();
+            final int id = view.getId();
+            if (id != View.NO_ID) {
+                lastKnownId = view.getId();
+            }
+        }
+        return lastKnownId;
+    }
+
+    /**
+     * The first step of a layout where we;
+     * - process adapter updates
+     * - decide which animation should run
+     * - save information about current views
+     * - If necessary, run predictive layout and save its information
+     */
+    private void dispatchLayoutStep1() {
+        mState.assertLayoutStep(State.STEP_START);
+        mState.mIsMeasuring = false;
+        eatRequestLayout();
+        mViewInfoStore.clear();
+        onEnterLayoutOrScroll();
+        processAdapterUpdatesAndSetAnimationFlags();
+        saveFocusInfo();
+        mState.mTrackOldChangeHolders = mState.mRunSimpleAnimations && mItemsChanged;
+        mItemsAddedOrRemoved = mItemsChanged = false;
+        mState.mInPreLayout = mState.mRunPredictiveAnimations;
+        mState.mItemCount = mAdapter.getItemCount();
+        findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);
+
+        if (mState.mRunSimpleAnimations) {
+            // Step 0: Find out where all non-removed items are, pre-layout
+            int count = mChildHelper.getChildCount();
+            for (int i = 0; i < count; ++i) {
+                final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
+                if (holder.shouldIgnore() || (holder.isInvalid() && !mAdapter.hasStableIds())) {
+                    continue;
+                }
+                final ItemHolderInfo animationInfo = mItemAnimator
+                        .recordPreLayoutInformation(mState, holder,
+                                ItemAnimator.buildAdapterChangeFlagsForAnimations(holder),
+                                holder.getUnmodifiedPayloads());
+                mViewInfoStore.addToPreLayout(holder, animationInfo);
+                if (mState.mTrackOldChangeHolders && holder.isUpdated() && !holder.isRemoved()
+                        && !holder.shouldIgnore() && !holder.isInvalid()) {
+                    long key = getChangedHolderKey(holder);
+                    // This is NOT the only place where a ViewHolder is added to old change holders
+                    // list. There is another case where:
+                    //    * A VH is currently hidden but not deleted
+                    //    * The hidden item is changed in the adapter
+                    //    * Layout manager decides to layout the item in the pre-Layout pass (step1)
+                    // When this case is detected, RV will un-hide that view and add to the old
+                    // change holders list.
+                    mViewInfoStore.addToOldChangeHolders(key, holder);
+                }
+            }
+        }
+        if (mState.mRunPredictiveAnimations) {
+            // Step 1: run prelayout: This will use the old positions of items. The layout manager
+            // is expected to layout everything, even removed items (though not to add removed
+            // items back to the container). This gives the pre-layout position of APPEARING views
+            // which come into existence as part of the real layout.
+
+            // Save old positions so that LayoutManager can run its mapping logic.
+            saveOldPositions();
+            final boolean didStructureChange = mState.mStructureChanged;
+            mState.mStructureChanged = false;
+            // temporarily disable flag because we are asking for previous layout
+            mLayout.onLayoutChildren(mRecycler, mState);
+            mState.mStructureChanged = didStructureChange;
+
+            for (int i = 0; i < mChildHelper.getChildCount(); ++i) {
+                final View child = mChildHelper.getChildAt(i);
+                final ViewHolder viewHolder = getChildViewHolderInt(child);
+                if (viewHolder.shouldIgnore()) {
+                    continue;
+                }
+                if (!mViewInfoStore.isInPreLayout(viewHolder)) {
+                    int flags = ItemAnimator.buildAdapterChangeFlagsForAnimations(viewHolder);
+                    boolean wasHidden = viewHolder
+                            .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+                    if (!wasHidden) {
+                        flags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;
+                    }
+                    final ItemHolderInfo animationInfo = mItemAnimator.recordPreLayoutInformation(
+                            mState, viewHolder, flags, viewHolder.getUnmodifiedPayloads());
+                    if (wasHidden) {
+                        recordAnimationInfoIfBouncedHiddenView(viewHolder, animationInfo);
+                    } else {
+                        mViewInfoStore.addToAppearedInPreLayoutHolders(viewHolder, animationInfo);
+                    }
+                }
+            }
+            // we don't process disappearing list because they may re-appear in post layout pass.
+            clearOldPositions();
+        } else {
+            clearOldPositions();
+        }
+        onExitLayoutOrScroll();
+        resumeRequestLayout(false);
+        mState.mLayoutStep = State.STEP_LAYOUT;
+    }
+
+    /**
+     * The second layout step where we do the actual layout of the views for the final state.
+     * This step might be run multiple times if necessary (e.g. measure).
+     */
+    private void dispatchLayoutStep2() {
+        eatRequestLayout();
+        onEnterLayoutOrScroll();
+        mState.assertLayoutStep(State.STEP_LAYOUT | State.STEP_ANIMATIONS);
+        mAdapterHelper.consumeUpdatesInOnePass();
+        mState.mItemCount = mAdapter.getItemCount();
+        mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;
+
+        // Step 2: Run layout
+        mState.mInPreLayout = false;
+        mLayout.onLayoutChildren(mRecycler, mState);
+
+        mState.mStructureChanged = false;
+        mPendingSavedState = null;
+
+        // onLayoutChildren may have caused client code to disable item animations; re-check
+        mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;
+        mState.mLayoutStep = State.STEP_ANIMATIONS;
+        onExitLayoutOrScroll();
+        resumeRequestLayout(false);
+    }
+
+    /**
+     * The final step of the layout where we save the information about views for animations,
+     * trigger animations and do any necessary cleanup.
+     */
+    private void dispatchLayoutStep3() {
+        mState.assertLayoutStep(State.STEP_ANIMATIONS);
+        eatRequestLayout();
+        onEnterLayoutOrScroll();
+        mState.mLayoutStep = State.STEP_START;
+        if (mState.mRunSimpleAnimations) {
+            // Step 3: Find out where things are now, and process change animations.
+            // traverse list in reverse because we may call animateChange in the loop which may
+            // remove the target view holder.
+            for (int i = mChildHelper.getChildCount() - 1; i >= 0; i--) {
+                ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
+                if (holder.shouldIgnore()) {
+                    continue;
+                }
+                long key = getChangedHolderKey(holder);
+                final ItemHolderInfo animationInfo = mItemAnimator
+                        .recordPostLayoutInformation(mState, holder);
+                ViewHolder oldChangeViewHolder = mViewInfoStore.getFromOldChangeHolders(key);
+                if (oldChangeViewHolder != null && !oldChangeViewHolder.shouldIgnore()) {
+                    // run a change animation
+
+                    // If an Item is CHANGED but the updated version is disappearing, it creates
+                    // a conflicting case.
+                    // Since a view that is marked as disappearing is likely to be going out of
+                    // bounds, we run a change animation. Both views will be cleaned automatically
+                    // once their animations finish.
+                    // On the other hand, if it is the same view holder instance, we run a
+                    // disappearing animation instead because we are not going to rebind the updated
+                    // VH unless it is enforced by the layout manager.
+                    final boolean oldDisappearing = mViewInfoStore.isDisappearing(
+                            oldChangeViewHolder);
+                    final boolean newDisappearing = mViewInfoStore.isDisappearing(holder);
+                    if (oldDisappearing && oldChangeViewHolder == holder) {
+                        // run disappear animation instead of change
+                        mViewInfoStore.addToPostLayout(holder, animationInfo);
+                    } else {
+                        final ItemHolderInfo preInfo = mViewInfoStore.popFromPreLayout(
+                                oldChangeViewHolder);
+                        // we add and remove so that any post info is merged.
+                        mViewInfoStore.addToPostLayout(holder, animationInfo);
+                        ItemHolderInfo postInfo = mViewInfoStore.popFromPostLayout(holder);
+                        if (preInfo == null) {
+                            handleMissingPreInfoForChangeError(key, holder, oldChangeViewHolder);
+                        } else {
+                            animateChange(oldChangeViewHolder, holder, preInfo, postInfo,
+                                    oldDisappearing, newDisappearing);
+                        }
+                    }
+                } else {
+                    mViewInfoStore.addToPostLayout(holder, animationInfo);
+                }
+            }
+
+            // Step 4: Process view info lists and trigger animations
+            mViewInfoStore.process(mViewInfoProcessCallback);
+        }
+
+        mLayout.removeAndRecycleScrapInt(mRecycler);
+        mState.mPreviousLayoutItemCount = mState.mItemCount;
+        mDataSetHasChangedAfterLayout = false;
+        mState.mRunSimpleAnimations = false;
+
+        mState.mRunPredictiveAnimations = false;
+        mLayout.mRequestedSimpleAnimations = false;
+        if (mRecycler.mChangedScrap != null) {
+            mRecycler.mChangedScrap.clear();
+        }
+        if (mLayout.mPrefetchMaxObservedInInitialPrefetch) {
+            // Initial prefetch has expanded cache, so reset until next prefetch.
+            // This prevents initial prefetches from expanding the cache permanently.
+            mLayout.mPrefetchMaxCountObserved = 0;
+            mLayout.mPrefetchMaxObservedInInitialPrefetch = false;
+            mRecycler.updateViewCacheSize();
+        }
+
+        mLayout.onLayoutCompleted(mState);
+        onExitLayoutOrScroll();
+        resumeRequestLayout(false);
+        mViewInfoStore.clear();
+        if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
+            dispatchOnScrolled(0, 0);
+        }
+        recoverFocusFromState();
+        resetFocusInfo();
+    }
+
+    /**
+     * This handles the case where there is an unexpected VH missing in the pre-layout map.
+     * <p>
+     * We might be able to detect the error in the application which will help the developer to
+     * resolve the issue.
+     * <p>
+     * If it is not an expected error, we at least print an error to notify the developer and ignore
+     * the animation.
+     *
+     * https://code.google.com/p/android/issues/detail?id=193958
+     *
+     * @param key The change key
+     * @param holder Current ViewHolder
+     * @param oldChangeViewHolder Changed ViewHolder
+     */
+    private void handleMissingPreInfoForChangeError(long key,
+            ViewHolder holder, ViewHolder oldChangeViewHolder) {
+        // check if two VH have the same key, if so, print that as an error
+        final int childCount = mChildHelper.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View view = mChildHelper.getChildAt(i);
+            ViewHolder other = getChildViewHolderInt(view);
+            if (other == holder) {
+                continue;
+            }
+            final long otherKey = getChangedHolderKey(other);
+            if (otherKey == key) {
+                if (mAdapter != null && mAdapter.hasStableIds()) {
+                    throw new IllegalStateException("Two different ViewHolders have the same stable"
+                            + " ID. Stable IDs in your adapter MUST BE unique and SHOULD NOT"
+                            + " change.\n ViewHolder 1:" + other + " \n View Holder 2:" + holder);
+                } else {
+                    throw new IllegalStateException("Two different ViewHolders have the same change"
+                            + " ID. This might happen due to inconsistent Adapter update events or"
+                            + " if the LayoutManager lays out the same View multiple times."
+                            + "\n ViewHolder 1:" + other + " \n View Holder 2:" + holder);
+                }
+            }
+        }
+        // Very unlikely to happen but if it does, notify the developer.
+        Log.e(TAG, "Problem while matching changed view holders with the new"
+                + "ones. The pre-layout information for the change holder " + oldChangeViewHolder
+                + " cannot be found but it is necessary for " + holder);
+    }
+
+    /**
+     * Records the animation information for a view holder that was bounced from hidden list. It
+     * also clears the bounce back flag.
+     */
+    void recordAnimationInfoIfBouncedHiddenView(ViewHolder viewHolder,
+            ItemHolderInfo animationInfo) {
+        // looks like this view bounced back from hidden list!
+        viewHolder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+        if (mState.mTrackOldChangeHolders && viewHolder.isUpdated()
+                && !viewHolder.isRemoved() && !viewHolder.shouldIgnore()) {
+            long key = getChangedHolderKey(viewHolder);
+            mViewInfoStore.addToOldChangeHolders(key, viewHolder);
+        }
+        mViewInfoStore.addToPreLayout(viewHolder, animationInfo);
+    }
+
+    private void findMinMaxChildLayoutPositions(int[] into) {
+        final int count = mChildHelper.getChildCount();
+        if (count == 0) {
+            into[0] = NO_POSITION;
+            into[1] = NO_POSITION;
+            return;
+        }
+        int minPositionPreLayout = Integer.MAX_VALUE;
+        int maxPositionPreLayout = Integer.MIN_VALUE;
+        for (int i = 0; i < count; ++i) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
+            if (holder.shouldIgnore()) {
+                continue;
+            }
+            final int pos = holder.getLayoutPosition();
+            if (pos < minPositionPreLayout) {
+                minPositionPreLayout = pos;
+            }
+            if (pos > maxPositionPreLayout) {
+                maxPositionPreLayout = pos;
+            }
+        }
+        into[0] = minPositionPreLayout;
+        into[1] = maxPositionPreLayout;
+    }
+
+    private boolean didChildRangeChange(int minPositionPreLayout, int maxPositionPreLayout) {
+        findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);
+        return mMinMaxLayoutPositions[0] != minPositionPreLayout
+                || mMinMaxLayoutPositions[1] != maxPositionPreLayout;
+    }
+
+    @Override
+    protected void removeDetachedView(View child, boolean animate) {
+        ViewHolder vh = getChildViewHolderInt(child);
+        if (vh != null) {
+            if (vh.isTmpDetached()) {
+                vh.clearTmpDetachFlag();
+            } else if (!vh.shouldIgnore()) {
+                throw new IllegalArgumentException("Called removeDetachedView with a view which"
+                        + " is not flagged as tmp detached." + vh);
+            }
+        }
+        dispatchChildDetached(child);
+        super.removeDetachedView(child, animate);
+    }
+
+    /**
+     * Returns a unique key to be used while handling change animations.
+     * It might be child's position or stable id depending on the adapter type.
+     */
+    long getChangedHolderKey(ViewHolder holder) {
+        return mAdapter.hasStableIds() ? holder.getItemId() : holder.mPosition;
+    }
+
+    void animateAppearance(@NonNull ViewHolder itemHolder,
+            @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
+        itemHolder.setIsRecyclable(false);
+        if (mItemAnimator.animateAppearance(itemHolder, preLayoutInfo, postLayoutInfo)) {
+            postAnimationRunner();
+        }
+    }
+
+    void animateDisappearance(@NonNull ViewHolder holder,
+            @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
+        addAnimatingView(holder);
+        holder.setIsRecyclable(false);
+        if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) {
+            postAnimationRunner();
+        }
+    }
+
+    private void animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
+            @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo,
+            boolean oldHolderDisappearing, boolean newHolderDisappearing) {
+        oldHolder.setIsRecyclable(false);
+        if (oldHolderDisappearing) {
+            addAnimatingView(oldHolder);
+        }
+        if (oldHolder != newHolder) {
+            if (newHolderDisappearing) {
+                addAnimatingView(newHolder);
+            }
+            oldHolder.mShadowedHolder = newHolder;
+            // old holder should disappear after animation ends
+            addAnimatingView(oldHolder);
+            mRecycler.unscrapView(oldHolder);
+            newHolder.setIsRecyclable(false);
+            newHolder.mShadowingHolder = oldHolder;
+        }
+        if (mItemAnimator.animateChange(oldHolder, newHolder, preInfo, postInfo)) {
+            postAnimationRunner();
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        Trace.beginSection(TRACE_ON_LAYOUT_TAG);
+        dispatchLayout();
+        Trace.endSection();
+        mFirstLayoutComplete = true;
+    }
+
+    @Override
+    public void requestLayout() {
+        if (mEatRequestLayout == 0 && !mLayoutFrozen) {
+            super.requestLayout();
+        } else {
+            mLayoutRequestEaten = true;
+        }
+    }
+
+    void markItemDecorInsetsDirty() {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = mChildHelper.getUnfilteredChildAt(i);
+            ((LayoutParams) child.getLayoutParams()).mInsetsDirty = true;
+        }
+        mRecycler.markItemDecorInsetsDirty();
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        super.draw(c);
+
+        final int count = mItemDecorations.size();
+        for (int i = 0; i < count; i++) {
+            mItemDecorations.get(i).onDrawOver(c, this, mState);
+        }
+        // TODO If padding is not 0 and clipChildrenToPadding is false, to draw glows properly, we
+        // need find children closest to edges. Not sure if it is worth the effort.
+        boolean needsInvalidate = false;
+        if (mLeftGlow != null && !mLeftGlow.isFinished()) {
+            final int restore = c.save();
+            final int padding = mClipToPadding ? getPaddingBottom() : 0;
+            c.rotate(270);
+            c.translate(-getHeight() + padding, 0);
+            needsInvalidate = mLeftGlow != null && mLeftGlow.draw(c);
+            c.restoreToCount(restore);
+        }
+        if (mTopGlow != null && !mTopGlow.isFinished()) {
+            final int restore = c.save();
+            if (mClipToPadding) {
+                c.translate(getPaddingLeft(), getPaddingTop());
+            }
+            needsInvalidate |= mTopGlow != null && mTopGlow.draw(c);
+            c.restoreToCount(restore);
+        }
+        if (mRightGlow != null && !mRightGlow.isFinished()) {
+            final int restore = c.save();
+            final int width = getWidth();
+            final int padding = mClipToPadding ? getPaddingTop() : 0;
+            c.rotate(90);
+            c.translate(-padding, -width);
+            needsInvalidate |= mRightGlow != null && mRightGlow.draw(c);
+            c.restoreToCount(restore);
+        }
+        if (mBottomGlow != null && !mBottomGlow.isFinished()) {
+            final int restore = c.save();
+            c.rotate(180);
+            if (mClipToPadding) {
+                c.translate(-getWidth() + getPaddingRight(), -getHeight() + getPaddingBottom());
+            } else {
+                c.translate(-getWidth(), -getHeight());
+            }
+            needsInvalidate |= mBottomGlow != null && mBottomGlow.draw(c);
+            c.restoreToCount(restore);
+        }
+
+        // If some views are animating, ItemDecorators are likely to move/change with them.
+        // Invalidate RecyclerView to re-draw decorators. This is still efficient because children's
+        // display lists are not invalidated.
+        if (!needsInvalidate && mItemAnimator != null && mItemDecorations.size() > 0
+                && mItemAnimator.isRunning()) {
+            needsInvalidate = true;
+        }
+
+        if (needsInvalidate) {
+            postInvalidateOnAnimation();
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas c) {
+        super.onDraw(c);
+
+        final int count = mItemDecorations.size();
+        for (int i = 0; i < count; i++) {
+            mItemDecorations.get(i).onDraw(c, this, mState);
+        }
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams && mLayout.checkLayoutParams((LayoutParams) p);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        if (mLayout == null) {
+            throw new IllegalStateException("RecyclerView has no LayoutManager");
+        }
+        return mLayout.generateDefaultLayoutParams();
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        if (mLayout == null) {
+            throw new IllegalStateException("RecyclerView has no LayoutManager");
+        }
+        return mLayout.generateLayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (mLayout == null) {
+            throw new IllegalStateException("RecyclerView has no LayoutManager");
+        }
+        return mLayout.generateLayoutParams(p);
+    }
+
+    /**
+     * Returns true if RecyclerView is currently running some animations.
+     * <p>
+     * If you want to be notified when animations are finished, use
+     * {@link ItemAnimator#isRunning(ItemAnimator.ItemAnimatorFinishedListener)}.
+     *
+     * @return True if there are some item animations currently running or waiting to be started.
+     */
+    public boolean isAnimating() {
+        return mItemAnimator != null && mItemAnimator.isRunning();
+    }
+
+    void saveOldPositions() {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (DEBUG && holder.mPosition == -1 && !holder.isRemoved()) {
+                throw new IllegalStateException("view holder cannot have position -1 unless it"
+                        + " is removed");
+            }
+            if (!holder.shouldIgnore()) {
+                holder.saveOldPosition();
+            }
+        }
+    }
+
+    void clearOldPositions() {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (!holder.shouldIgnore()) {
+                holder.clearOldPosition();
+            }
+        }
+        mRecycler.clearOldPositions();
+    }
+
+    void offsetPositionRecordsForMove(int from, int to) {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        final int start, end, inBetweenOffset;
+        if (from < to) {
+            start = from;
+            end = to;
+            inBetweenOffset = -1;
+        } else {
+            start = to;
+            end = from;
+            inBetweenOffset = 1;
+        }
+
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder == null || holder.mPosition < start || holder.mPosition > end) {
+                continue;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "offsetPositionRecordsForMove attached child " + i + " holder "
+                        + holder);
+            }
+            if (holder.mPosition == from) {
+                holder.offsetPosition(to - from, false);
+            } else {
+                holder.offsetPosition(inBetweenOffset, false);
+            }
+
+            mState.mStructureChanged = true;
+        }
+        mRecycler.offsetPositionRecordsForMove(from, to);
+        requestLayout();
+    }
+
+    void offsetPositionRecordsForInsert(int positionStart, int itemCount) {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.shouldIgnore() && holder.mPosition >= positionStart) {
+                if (DEBUG) {
+                    Log.d(TAG, "offsetPositionRecordsForInsert attached child " + i + " holder "
+                            + holder + " now at position " + (holder.mPosition + itemCount));
+                }
+                holder.offsetPosition(itemCount, false);
+                mState.mStructureChanged = true;
+            }
+        }
+        mRecycler.offsetPositionRecordsForInsert(positionStart, itemCount);
+        requestLayout();
+    }
+
+    void offsetPositionRecordsForRemove(int positionStart, int itemCount,
+            boolean applyToPreLayout) {
+        final int positionEnd = positionStart + itemCount;
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.shouldIgnore()) {
+                if (holder.mPosition >= positionEnd) {
+                    if (DEBUG) {
+                        Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i
+                                + " holder " + holder + " now at position "
+                                + (holder.mPosition - itemCount));
+                    }
+                    holder.offsetPosition(-itemCount, applyToPreLayout);
+                    mState.mStructureChanged = true;
+                } else if (holder.mPosition >= positionStart) {
+                    if (DEBUG) {
+                        Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i
+                                + " holder " + holder + " now REMOVED");
+                    }
+                    holder.flagRemovedAndOffsetPosition(positionStart - 1, -itemCount,
+                            applyToPreLayout);
+                    mState.mStructureChanged = true;
+                }
+            }
+        }
+        mRecycler.offsetPositionRecordsForRemove(positionStart, itemCount, applyToPreLayout);
+        requestLayout();
+    }
+
+    /**
+     * Rebind existing views for the given range, or create as needed.
+     *
+     * @param positionStart Adapter position to start at
+     * @param itemCount Number of views that must explicitly be rebound
+     */
+    void viewRangeUpdate(int positionStart, int itemCount, Object payload) {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        final int positionEnd = positionStart + itemCount;
+
+        for (int i = 0; i < childCount; i++) {
+            final View child = mChildHelper.getUnfilteredChildAt(i);
+            final ViewHolder holder = getChildViewHolderInt(child);
+            if (holder == null || holder.shouldIgnore()) {
+                continue;
+            }
+            if (holder.mPosition >= positionStart && holder.mPosition < positionEnd) {
+                // We re-bind these view holders after pre-processing is complete so that
+                // ViewHolders have their final positions assigned.
+                holder.addFlags(ViewHolder.FLAG_UPDATE);
+                holder.addChangePayload(payload);
+                // lp cannot be null since we get ViewHolder from it.
+                ((LayoutParams) child.getLayoutParams()).mInsetsDirty = true;
+            }
+        }
+        mRecycler.viewRangeUpdate(positionStart, itemCount);
+    }
+
+    boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) {
+        return mItemAnimator == null || mItemAnimator.canReuseUpdatedViewHolder(viewHolder,
+                viewHolder.getUnmodifiedPayloads());
+    }
+
+
+    /**
+     * Call this method to signal that *all* adapter content has changed (generally, because of
+     * swapAdapter, or notifyDataSetChanged), and that once layout occurs, all attached items should
+     * be discarded or animated. Note that this work is deferred because RecyclerView requires a
+     * layout to resolve non-incremental changes to the data set.
+     *
+     * Attached items are labeled as position unknown, and may no longer be cached.
+     *
+     * It is still possible for items to be prefetched while mDataSetHasChangedAfterLayout == true,
+     * so calling this method *must* be associated with marking the cache invalid, so that the
+     * only valid items that remain in the cache, once layout occurs, are prefetched items.
+     */
+    void setDataSetChangedAfterLayout() {
+        if (mDataSetHasChangedAfterLayout) {
+            return;
+        }
+        mDataSetHasChangedAfterLayout = true;
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.shouldIgnore()) {
+                holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
+            }
+        }
+        mRecycler.setAdapterPositionsAsUnknown();
+
+        // immediately mark all views as invalid, so prefetched views can be
+        // differentiated from views bound to previous data set - both in children, and cache
+        markKnownViewsInvalid();
+    }
+
+    /**
+     * Mark all known views as invalid. Used in response to a, "the whole world might have changed"
+     * data change event.
+     */
+    void markKnownViewsInvalid() {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.shouldIgnore()) {
+                holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
+            }
+        }
+        markItemDecorInsetsDirty();
+        mRecycler.markKnownViewsInvalid();
+    }
+
+    /**
+     * Invalidates all ItemDecorations. If RecyclerView has item decorations, calling this method
+     * will trigger a {@link #requestLayout()} call.
+     */
+    public void invalidateItemDecorations() {
+        if (mItemDecorations.size() == 0) {
+            return;
+        }
+        if (mLayout != null) {
+            mLayout.assertNotInLayoutOrScroll("Cannot invalidate item decorations during a scroll"
+                    + " or layout");
+        }
+        markItemDecorInsetsDirty();
+        requestLayout();
+    }
+
+    /**
+     * Returns true if the RecyclerView should attempt to preserve currently focused Adapter Item's
+     * focus even if the View representing the Item is replaced during a layout calculation.
+     * <p>
+     * By default, this value is {@code true}.
+     *
+     * @return True if the RecyclerView will try to preserve focused Item after a layout if it loses
+     * focus.
+     *
+     * @see #setPreserveFocusAfterLayout(boolean)
+     */
+    public boolean getPreserveFocusAfterLayout() {
+        return mPreserveFocusAfterLayout;
+    }
+
+    /**
+     * Set whether the RecyclerView should try to keep the same Item focused after a layout
+     * calculation or not.
+     * <p>
+     * Usually, LayoutManagers keep focused views visible before and after layout but sometimes,
+     * views may lose focus during a layout calculation as their state changes or they are replaced
+     * with another view due to type change or animation. In these cases, RecyclerView can request
+     * focus on the new view automatically.
+     *
+     * @param preserveFocusAfterLayout Whether RecyclerView should preserve focused Item during a
+     *                                 layout calculations. Defaults to true.
+     *
+     * @see #getPreserveFocusAfterLayout()
+     */
+    public void setPreserveFocusAfterLayout(boolean preserveFocusAfterLayout) {
+        mPreserveFocusAfterLayout = preserveFocusAfterLayout;
+    }
+
+    /**
+     * Retrieve the {@link ViewHolder} for the given child view.
+     *
+     * @param child Child of this RecyclerView to query for its ViewHolder
+     * @return The child view's ViewHolder
+     */
+    public ViewHolder getChildViewHolder(View child) {
+        final ViewParent parent = child.getParent();
+        if (parent != null && parent != this) {
+            throw new IllegalArgumentException("View " + child + " is not a direct child of "
+                    + this);
+        }
+        return getChildViewHolderInt(child);
+    }
+
+    /**
+     * Traverses the ancestors of the given view and returns the item view that contains it and
+     * also a direct child of the RecyclerView. This returned view can be used to get the
+     * ViewHolder by calling {@link #getChildViewHolder(View)}.
+     *
+     * @param view The view that is a descendant of the RecyclerView.
+     *
+     * @return The direct child of the RecyclerView which contains the given view or null if the
+     * provided view is not a descendant of this RecyclerView.
+     *
+     * @see #getChildViewHolder(View)
+     * @see #findContainingViewHolder(View)
+     */
+    @Nullable
+    public View findContainingItemView(View view) {
+        ViewParent parent = view.getParent();
+        while (parent != null && parent != this && parent instanceof View) {
+            view = (View) parent;
+            parent = view.getParent();
+        }
+        return parent == this ? view : null;
+    }
+
+    /**
+     * Returns the ViewHolder that contains the given view.
+     *
+     * @param view The view that is a descendant of the RecyclerView.
+     *
+     * @return The ViewHolder that contains the given view or null if the provided view is not a
+     * descendant of this RecyclerView.
+     */
+    @Nullable
+    public ViewHolder findContainingViewHolder(View view) {
+        View itemView = findContainingItemView(view);
+        return itemView == null ? null : getChildViewHolder(itemView);
+    }
+
+
+    static ViewHolder getChildViewHolderInt(View child) {
+        if (child == null) {
+            return null;
+        }
+        return ((LayoutParams) child.getLayoutParams()).mViewHolder;
+    }
+
+    /**
+     * @deprecated use {@link #getChildAdapterPosition(View)} or
+     * {@link #getChildLayoutPosition(View)}.
+     */
+    @Deprecated
+    public int getChildPosition(View child) {
+        return getChildAdapterPosition(child);
+    }
+
+    /**
+     * Return the adapter position that the given child view corresponds to.
+     *
+     * @param child Child View to query
+     * @return Adapter position corresponding to the given view or {@link #NO_POSITION}
+     */
+    public int getChildAdapterPosition(View child) {
+        final ViewHolder holder = getChildViewHolderInt(child);
+        return holder != null ? holder.getAdapterPosition() : NO_POSITION;
+    }
+
+    /**
+     * Return the adapter position of the given child view as of the latest completed layout pass.
+     * <p>
+     * This position may not be equal to Item's adapter position if there are pending changes
+     * in the adapter which have not been reflected to the layout yet.
+     *
+     * @param child Child View to query
+     * @return Adapter position of the given View as of last layout pass or {@link #NO_POSITION} if
+     * the View is representing a removed item.
+     */
+    public int getChildLayoutPosition(View child) {
+        final ViewHolder holder = getChildViewHolderInt(child);
+        return holder != null ? holder.getLayoutPosition() : NO_POSITION;
+    }
+
+    /**
+     * Return the stable item id that the given child view corresponds to.
+     *
+     * @param child Child View to query
+     * @return Item id corresponding to the given view or {@link #NO_ID}
+     */
+    public long getChildItemId(View child) {
+        if (mAdapter == null || !mAdapter.hasStableIds()) {
+            return NO_ID;
+        }
+        final ViewHolder holder = getChildViewHolderInt(child);
+        return holder != null ? holder.getItemId() : NO_ID;
+    }
+
+    /**
+     * @deprecated use {@link #findViewHolderForLayoutPosition(int)} or
+     * {@link #findViewHolderForAdapterPosition(int)}
+     */
+    @Deprecated
+    public ViewHolder findViewHolderForPosition(int position) {
+        return findViewHolderForPosition(position, false);
+    }
+
+    /**
+     * Return the ViewHolder for the item in the given position of the data set as of the latest
+     * layout pass.
+     * <p>
+     * This method checks only the children of RecyclerView. If the item at the given
+     * <code>position</code> is not laid out, it <em>will not</em> create a new one.
+     * <p>
+     * Note that when Adapter contents change, ViewHolder positions are not updated until the
+     * next layout calculation. If there are pending adapter updates, the return value of this
+     * method may not match your adapter contents. You can use
+     * #{@link ViewHolder#getAdapterPosition()} to get the current adapter position of a ViewHolder.
+     * <p>
+     * When the ItemAnimator is running a change animation, there might be 2 ViewHolders
+     * with the same layout position representing the same Item. In this case, the updated
+     * ViewHolder will be returned.
+     *
+     * @param position The position of the item in the data set of the adapter
+     * @return The ViewHolder at <code>position</code> or null if there is no such item
+     */
+    public ViewHolder findViewHolderForLayoutPosition(int position) {
+        return findViewHolderForPosition(position, false);
+    }
+
+    /**
+     * Return the ViewHolder for the item in the given position of the data set. Unlike
+     * {@link #findViewHolderForLayoutPosition(int)} this method takes into account any pending
+     * adapter changes that may not be reflected to the layout yet. On the other hand, if
+     * {@link Adapter#notifyDataSetChanged()} has been called but the new layout has not been
+     * calculated yet, this method will return <code>null</code> since the new positions of views
+     * are unknown until the layout is calculated.
+     * <p>
+     * This method checks only the children of RecyclerView. If the item at the given
+     * <code>position</code> is not laid out, it <em>will not</em> create a new one.
+     * <p>
+     * When the ItemAnimator is running a change animation, there might be 2 ViewHolders
+     * representing the same Item. In this case, the updated ViewHolder will be returned.
+     *
+     * @param position The position of the item in the data set of the adapter
+     * @return The ViewHolder at <code>position</code> or null if there is no such item
+     */
+    public ViewHolder findViewHolderForAdapterPosition(int position) {
+        if (mDataSetHasChangedAfterLayout) {
+            return null;
+        }
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        // hidden VHs are not preferred but if that is the only one we find, we rather return it
+        ViewHolder hidden = null;
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.isRemoved()
+                    && getAdapterPositionFor(holder) == position) {
+                if (mChildHelper.isHidden(holder.itemView)) {
+                    hidden = holder;
+                } else {
+                    return holder;
+                }
+            }
+        }
+        return hidden;
+    }
+
+    ViewHolder findViewHolderForPosition(int position, boolean checkNewPosition) {
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        ViewHolder hidden = null;
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.isRemoved()) {
+                if (checkNewPosition) {
+                    if (holder.mPosition != position) {
+                        continue;
+                    }
+                } else if (holder.getLayoutPosition() != position) {
+                    continue;
+                }
+                if (mChildHelper.isHidden(holder.itemView)) {
+                    hidden = holder;
+                } else {
+                    return holder;
+                }
+            }
+        }
+        // This method should not query cached views. It creates a problem during adapter updates
+        // when we are dealing with already laid out views. Also, for the public method, it is more
+        // reasonable to return null if position is not laid out.
+        return hidden;
+    }
+
+    /**
+     * Return the ViewHolder for the item with the given id. The RecyclerView must
+     * use an Adapter with {@link Adapter#setHasStableIds(boolean) stableIds} to
+     * return a non-null value.
+     * <p>
+     * This method checks only the children of RecyclerView. If the item with the given
+     * <code>id</code> is not laid out, it <em>will not</em> create a new one.
+     *
+     * When the ItemAnimator is running a change animation, there might be 2 ViewHolders with the
+     * same id. In this case, the updated ViewHolder will be returned.
+     *
+     * @param id The id for the requested item
+     * @return The ViewHolder with the given <code>id</code> or null if there is no such item
+     */
+    public ViewHolder findViewHolderForItemId(long id) {
+        if (mAdapter == null || !mAdapter.hasStableIds()) {
+            return null;
+        }
+        final int childCount = mChildHelper.getUnfilteredChildCount();
+        ViewHolder hidden = null;
+        for (int i = 0; i < childCount; i++) {
+            final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
+            if (holder != null && !holder.isRemoved() && holder.getItemId() == id) {
+                if (mChildHelper.isHidden(holder.itemView)) {
+                    hidden = holder;
+                } else {
+                    return holder;
+                }
+            }
+        }
+        return hidden;
+    }
+
+    /**
+     * Find the topmost view under the given point.
+     *
+     * @param x Horizontal position in pixels to search
+     * @param y Vertical position in pixels to search
+     * @return The child view under (x, y) or null if no matching child is found
+     */
+    public View findChildViewUnder(float x, float y) {
+        final int count = mChildHelper.getChildCount();
+        for (int i = count - 1; i >= 0; i--) {
+            final View child = mChildHelper.getChildAt(i);
+            final float translationX = child.getTranslationX();
+            final float translationY = child.getTranslationY();
+            if (x >= child.getLeft() + translationX
+                    && x <= child.getRight() + translationX
+                    && y >= child.getTop() + translationY
+                    && y <= child.getBottom() + translationY) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    /**
+     * Offset the bounds of all child views by <code>dy</code> pixels.
+     * Useful for implementing simple scrolling in {@link LayoutManager LayoutManagers}.
+     *
+     * @param dy Vertical pixel offset to apply to the bounds of all child views
+     */
+    public void offsetChildrenVertical(int dy) {
+        final int childCount = mChildHelper.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            mChildHelper.getChildAt(i).offsetTopAndBottom(dy);
+        }
+    }
+
+    /**
+     * Called when an item view is attached to this RecyclerView.
+     *
+     * <p>Subclasses of RecyclerView may want to perform extra bookkeeping or modifications
+     * of child views as they become attached. This will be called before a
+     * {@link LayoutManager} measures or lays out the view and is a good time to perform these
+     * changes.</p>
+     *
+     * @param child Child view that is now attached to this RecyclerView and its associated window
+     */
+    public void onChildAttachedToWindow(View child) {
+    }
+
+    /**
+     * Called when an item view is detached from this RecyclerView.
+     *
+     * <p>Subclasses of RecyclerView may want to perform extra bookkeeping or modifications
+     * of child views as they become detached. This will be called as a
+     * {@link LayoutManager} fully detaches the child view from the parent and its window.</p>
+     *
+     * @param child Child view that is now detached from this RecyclerView and its associated window
+     */
+    public void onChildDetachedFromWindow(View child) {
+    }
+
+    /**
+     * Offset the bounds of all child views by <code>dx</code> pixels.
+     * Useful for implementing simple scrolling in {@link LayoutManager LayoutManagers}.
+     *
+     * @param dx Horizontal pixel offset to apply to the bounds of all child views
+     */
+    public void offsetChildrenHorizontal(int dx) {
+        final int childCount = mChildHelper.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            mChildHelper.getChildAt(i).offsetLeftAndRight(dx);
+        }
+    }
+
+    /**
+     * Returns the bounds of the view including its decoration and margins.
+     *
+     * @param view The view element to check
+     * @param outBounds A rect that will receive the bounds of the element including its
+     *                  decoration and margins.
+     */
+    public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
+        getDecoratedBoundsWithMarginsInt(view, outBounds);
+    }
+
+    static void getDecoratedBoundsWithMarginsInt(View view, Rect outBounds) {
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        final Rect insets = lp.mDecorInsets;
+        outBounds.set(view.getLeft() - insets.left - lp.leftMargin,
+                view.getTop() - insets.top - lp.topMargin,
+                view.getRight() + insets.right + lp.rightMargin,
+                view.getBottom() + insets.bottom + lp.bottomMargin);
+    }
+
+    Rect getItemDecorInsetsForChild(View child) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        if (!lp.mInsetsDirty) {
+            return lp.mDecorInsets;
+        }
+
+        if (mState.isPreLayout() && (lp.isItemChanged() || lp.isViewInvalid())) {
+            // changed/invalid items should not be updated until they are rebound.
+            return lp.mDecorInsets;
+        }
+        final Rect insets = lp.mDecorInsets;
+        insets.set(0, 0, 0, 0);
+        final int decorCount = mItemDecorations.size();
+        for (int i = 0; i < decorCount; i++) {
+            mTempRect.set(0, 0, 0, 0);
+            mItemDecorations.get(i).getItemOffsets(mTempRect, child, this, mState);
+            insets.left += mTempRect.left;
+            insets.top += mTempRect.top;
+            insets.right += mTempRect.right;
+            insets.bottom += mTempRect.bottom;
+        }
+        lp.mInsetsDirty = false;
+        return insets;
+    }
+
+    /**
+     * Called when the scroll position of this RecyclerView changes. Subclasses should use
+     * this method to respond to scrolling within the adapter's data set instead of an explicit
+     * listener.
+     *
+     * <p>This method will always be invoked before listeners. If a subclass needs to perform
+     * any additional upkeep or bookkeeping after scrolling but before listeners run,
+     * this is a good place to do so.</p>
+     *
+     * <p>This differs from {@link View#onScrollChanged(int, int, int, int)} in that it receives
+     * the distance scrolled in either direction within the adapter's data set instead of absolute
+     * scroll coordinates. Since RecyclerView cannot compute the absolute scroll position from
+     * any arbitrary point in the data set, <code>onScrollChanged</code> will always receive
+     * the current {@link View#getScrollX()} and {@link View#getScrollY()} values which
+     * do not correspond to the data set scroll position. However, some subclasses may choose
+     * to use these fields as special offsets.</p>
+     *
+     * @param dx horizontal distance scrolled in pixels
+     * @param dy vertical distance scrolled in pixels
+     */
+    public void onScrolled(int dx, int dy) {
+        // Do nothing
+    }
+
+    void dispatchOnScrolled(int hresult, int vresult) {
+        mDispatchScrollCounter++;
+        // Pass the current scrollX/scrollY values; no actual change in these properties occurred
+        // but some general-purpose code may choose to respond to changes this way.
+        final int scrollX = getScrollX();
+        final int scrollY = getScrollY();
+        onScrollChanged(scrollX, scrollY, scrollX, scrollY);
+
+        // Pass the real deltas to onScrolled, the RecyclerView-specific method.
+        onScrolled(hresult, vresult);
+
+        // Invoke listeners last. Subclassed view methods always handle the event first.
+        // All internal state is consistent by the time listeners are invoked.
+        if (mScrollListener != null) {
+            mScrollListener.onScrolled(this, hresult, vresult);
+        }
+        if (mScrollListeners != null) {
+            for (int i = mScrollListeners.size() - 1; i >= 0; i--) {
+                mScrollListeners.get(i).onScrolled(this, hresult, vresult);
+            }
+        }
+        mDispatchScrollCounter--;
+    }
+
+    /**
+     * Called when the scroll state of this RecyclerView changes. Subclasses should use this
+     * method to respond to state changes instead of an explicit listener.
+     *
+     * <p>This method will always be invoked before listeners, but after the LayoutManager
+     * responds to the scroll state change.</p>
+     *
+     * @param state the new scroll state, one of {@link #SCROLL_STATE_IDLE},
+     *              {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}
+     */
+    public void onScrollStateChanged(int state) {
+        // Do nothing
+    }
+
+    void dispatchOnScrollStateChanged(int state) {
+        // Let the LayoutManager go first; this allows it to bring any properties into
+        // a consistent state before the RecyclerView subclass responds.
+        if (mLayout != null) {
+            mLayout.onScrollStateChanged(state);
+        }
+
+        // Let the RecyclerView subclass handle this event next; any LayoutManager property
+        // changes will be reflected by this time.
+        onScrollStateChanged(state);
+
+        // Listeners go last. All other internal state is consistent by this point.
+        if (mScrollListener != null) {
+            mScrollListener.onScrollStateChanged(this, state);
+        }
+        if (mScrollListeners != null) {
+            for (int i = mScrollListeners.size() - 1; i >= 0; i--) {
+                mScrollListeners.get(i).onScrollStateChanged(this, state);
+            }
+        }
+    }
+
+    /**
+     * Returns whether there are pending adapter updates which are not yet applied to the layout.
+     * <p>
+     * If this method returns <code>true</code>, it means that what user is currently seeing may not
+     * reflect them adapter contents (depending on what has changed).
+     * You may use this information to defer or cancel some operations.
+     * <p>
+     * This method returns true if RecyclerView has not yet calculated the first layout after it is
+     * attached to the Window or the Adapter has been replaced.
+     *
+     * @return True if there are some adapter updates which are not yet reflected to layout or false
+     * if layout is up to date.
+     */
+    public boolean hasPendingAdapterUpdates() {
+        return !mFirstLayoutComplete || mDataSetHasChangedAfterLayout
+                || mAdapterHelper.hasPendingUpdates();
+    }
+
+    class ViewFlinger implements Runnable {
+        private int mLastFlingX;
+        private int mLastFlingY;
+        private OverScroller mScroller;
+        Interpolator mInterpolator = sQuinticInterpolator;
+
+
+        // When set to true, postOnAnimation callbacks are delayed until the run method completes
+        private boolean mEatRunOnAnimationRequest = false;
+
+        // Tracks if postAnimationCallback should be re-attached when it is done
+        private boolean mReSchedulePostAnimationCallback = false;
+
+        ViewFlinger() {
+            mScroller = new OverScroller(getContext(), sQuinticInterpolator);
+        }
+
+        @Override
+        public void run() {
+            if (mLayout == null) {
+                stop();
+                return; // no layout, cannot scroll.
+            }
+            disableRunOnAnimationRequests();
+            consumePendingUpdateOperations();
+            // keep a local reference so that if it is changed during onAnimation method, it won't
+            // cause unexpected behaviors
+            final OverScroller scroller = mScroller;
+            final SmoothScroller smoothScroller = mLayout.mSmoothScroller;
+            if (scroller.computeScrollOffset()) {
+                final int x = scroller.getCurrX();
+                final int y = scroller.getCurrY();
+                final int dx = x - mLastFlingX;
+                final int dy = y - mLastFlingY;
+                int hresult = 0;
+                int vresult = 0;
+                mLastFlingX = x;
+                mLastFlingY = y;
+                int overscrollX = 0, overscrollY = 0;
+                if (mAdapter != null) {
+                    eatRequestLayout();
+                    onEnterLayoutOrScroll();
+                    Trace.beginSection(TRACE_SCROLL_TAG);
+                    if (dx != 0) {
+                        hresult = mLayout.scrollHorizontallyBy(dx, mRecycler, mState);
+                        overscrollX = dx - hresult;
+                    }
+                    if (dy != 0) {
+                        vresult = mLayout.scrollVerticallyBy(dy, mRecycler, mState);
+                        overscrollY = dy - vresult;
+                    }
+                    Trace.endSection();
+                    repositionShadowingViews();
+
+                    onExitLayoutOrScroll();
+                    resumeRequestLayout(false);
+
+                    if (smoothScroller != null && !smoothScroller.isPendingInitialRun()
+                            && smoothScroller.isRunning()) {
+                        final int adapterSize = mState.getItemCount();
+                        if (adapterSize == 0) {
+                            smoothScroller.stop();
+                        } else if (smoothScroller.getTargetPosition() >= adapterSize) {
+                            smoothScroller.setTargetPosition(adapterSize - 1);
+                            smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
+                        } else {
+                            smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
+                        }
+                    }
+                }
+                if (!mItemDecorations.isEmpty()) {
+                    invalidate();
+                }
+                if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
+                    considerReleasingGlowsOnScroll(dx, dy);
+                }
+                if (overscrollX != 0 || overscrollY != 0) {
+                    final int vel = (int) scroller.getCurrVelocity();
+
+                    int velX = 0;
+                    if (overscrollX != x) {
+                        velX = overscrollX < 0 ? -vel : overscrollX > 0 ? vel : 0;
+                    }
+
+                    int velY = 0;
+                    if (overscrollY != y) {
+                        velY = overscrollY < 0 ? -vel : overscrollY > 0 ? vel : 0;
+                    }
+
+                    if (getOverScrollMode() != View.OVER_SCROLL_NEVER) {
+                        absorbGlows(velX, velY);
+                    }
+                    if ((velX != 0 || overscrollX == x || scroller.getFinalX() == 0)
+                            && (velY != 0 || overscrollY == y || scroller.getFinalY() == 0)) {
+                        scroller.abortAnimation();
+                    }
+                }
+                if (hresult != 0 || vresult != 0) {
+                    dispatchOnScrolled(hresult, vresult);
+                }
+
+                if (!awakenScrollBars()) {
+                    invalidate();
+                }
+
+                final boolean fullyConsumedVertical = dy != 0 && mLayout.canScrollVertically()
+                        && vresult == dy;
+                final boolean fullyConsumedHorizontal = dx != 0 && mLayout.canScrollHorizontally()
+                        && hresult == dx;
+                final boolean fullyConsumedAny = (dx == 0 && dy == 0) || fullyConsumedHorizontal
+                        || fullyConsumedVertical;
+
+                if (scroller.isFinished() || !fullyConsumedAny) {
+                    setScrollState(SCROLL_STATE_IDLE); // setting state to idle will stop this.
+                    if (ALLOW_THREAD_GAP_WORK) {
+                        mPrefetchRegistry.clearPrefetchPositions();
+                    }
+                } else {
+                    postOnAnimation();
+                    if (mGapWorker != null) {
+                        mGapWorker.postFromTraversal(RecyclerView.this, dx, dy);
+                    }
+                }
+            }
+            // call this after the onAnimation is complete not to have inconsistent callbacks etc.
+            if (smoothScroller != null) {
+                if (smoothScroller.isPendingInitialRun()) {
+                    smoothScroller.onAnimation(0, 0);
+                }
+                if (!mReSchedulePostAnimationCallback) {
+                    smoothScroller.stop(); //stop if it does not trigger any scroll
+                }
+            }
+            enableRunOnAnimationRequests();
+        }
+
+        private void disableRunOnAnimationRequests() {
+            mReSchedulePostAnimationCallback = false;
+            mEatRunOnAnimationRequest = true;
+        }
+
+        private void enableRunOnAnimationRequests() {
+            mEatRunOnAnimationRequest = false;
+            if (mReSchedulePostAnimationCallback) {
+                postOnAnimation();
+            }
+        }
+
+        void postOnAnimation() {
+            if (mEatRunOnAnimationRequest) {
+                mReSchedulePostAnimationCallback = true;
+            } else {
+                removeCallbacks(this);
+                RecyclerView.this.postOnAnimation(this);
+            }
+        }
+
+        public void fling(int velocityX, int velocityY) {
+            setScrollState(SCROLL_STATE_SETTLING);
+            mLastFlingX = mLastFlingY = 0;
+            mScroller.fling(0, 0, velocityX, velocityY,
+                    Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+            postOnAnimation();
+        }
+
+        public void smoothScrollBy(int dx, int dy) {
+            smoothScrollBy(dx, dy, 0, 0);
+        }
+
+        public void smoothScrollBy(int dx, int dy, int vx, int vy) {
+            smoothScrollBy(dx, dy, computeScrollDuration(dx, dy, vx, vy));
+        }
+
+        private float distanceInfluenceForSnapDuration(float f) {
+            f -= 0.5f; // center the values about 0.
+            f *= 0.3f * Math.PI / 2.0f;
+            return (float) Math.sin(f);
+        }
+
+        private int computeScrollDuration(int dx, int dy, int vx, int vy) {
+            final int absDx = Math.abs(dx);
+            final int absDy = Math.abs(dy);
+            final boolean horizontal = absDx > absDy;
+            final int velocity = (int) Math.sqrt(vx * vx + vy * vy);
+            final int delta = (int) Math.sqrt(dx * dx + dy * dy);
+            final int containerSize = horizontal ? getWidth() : getHeight();
+            final int halfContainerSize = containerSize / 2;
+            final float distanceRatio = Math.min(1.f, 1.f * delta / containerSize);
+            final float distance = halfContainerSize + halfContainerSize
+                    * distanceInfluenceForSnapDuration(distanceRatio);
+
+            final int duration;
+            if (velocity > 0) {
+                duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
+            } else {
+                float absDelta = (float) (horizontal ? absDx : absDy);
+                duration = (int) (((absDelta / containerSize) + 1) * 300);
+            }
+            return Math.min(duration, MAX_SCROLL_DURATION);
+        }
+
+        public void smoothScrollBy(int dx, int dy, int duration) {
+            smoothScrollBy(dx, dy, duration, sQuinticInterpolator);
+        }
+
+        public void smoothScrollBy(int dx, int dy, Interpolator interpolator) {
+            smoothScrollBy(dx, dy, computeScrollDuration(dx, dy, 0, 0),
+                    interpolator == null ? sQuinticInterpolator : interpolator);
+        }
+
+        public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {
+            if (mInterpolator != interpolator) {
+                mInterpolator = interpolator;
+                mScroller = new OverScroller(getContext(), interpolator);
+            }
+            setScrollState(SCROLL_STATE_SETTLING);
+            mLastFlingX = mLastFlingY = 0;
+            mScroller.startScroll(0, 0, dx, dy, duration);
+            postOnAnimation();
+        }
+
+        public void stop() {
+            removeCallbacks(this);
+            mScroller.abortAnimation();
+        }
+
+    }
+
+    void repositionShadowingViews() {
+        // Fix up shadow views used by change animations
+        int count = mChildHelper.getChildCount();
+        for (int i = 0; i < count; i++) {
+            View view = mChildHelper.getChildAt(i);
+            ViewHolder holder = getChildViewHolder(view);
+            if (holder != null && holder.mShadowingHolder != null) {
+                View shadowingView = holder.mShadowingHolder.itemView;
+                int left = view.getLeft();
+                int top = view.getTop();
+                if (left != shadowingView.getLeft() ||  top != shadowingView.getTop()) {
+                    shadowingView.layout(left, top,
+                            left + shadowingView.getWidth(),
+                            top + shadowingView.getHeight());
+                }
+            }
+        }
+    }
+
+    private class RecyclerViewDataObserver extends AdapterDataObserver {
+        RecyclerViewDataObserver() {
+        }
+
+        @Override
+        public void onChanged() {
+            assertNotInLayoutOrScroll(null);
+            mState.mStructureChanged = true;
+
+            setDataSetChangedAfterLayout();
+            if (!mAdapterHelper.hasPendingUpdates()) {
+                requestLayout();
+            }
+        }
+
+        @Override
+        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+            assertNotInLayoutOrScroll(null);
+            if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
+                triggerUpdateProcessor();
+            }
+        }
+
+        @Override
+        public void onItemRangeInserted(int positionStart, int itemCount) {
+            assertNotInLayoutOrScroll(null);
+            if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
+                triggerUpdateProcessor();
+            }
+        }
+
+        @Override
+        public void onItemRangeRemoved(int positionStart, int itemCount) {
+            assertNotInLayoutOrScroll(null);
+            if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
+                triggerUpdateProcessor();
+            }
+        }
+
+        @Override
+        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+            assertNotInLayoutOrScroll(null);
+            if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
+                triggerUpdateProcessor();
+            }
+        }
+
+        void triggerUpdateProcessor() {
+            if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
+                RecyclerView.this.postOnAnimation(mUpdateChildViewsRunnable);
+            } else {
+                mAdapterUpdateDuringMeasure = true;
+                requestLayout();
+            }
+        }
+    }
+
+    /**
+     * RecycledViewPool lets you share Views between multiple RecyclerViews.
+     * <p>
+     * If you want to recycle views across RecyclerViews, create an instance of RecycledViewPool
+     * and use {@link RecyclerView#setRecycledViewPool(RecycledViewPool)}.
+     * <p>
+     * RecyclerView automatically creates a pool for itself if you don't provide one.
+     *
+     */
+    public static class RecycledViewPool {
+        private static final int DEFAULT_MAX_SCRAP = 5;
+
+        /**
+         * Tracks both pooled holders, as well as create/bind timing metadata for the given type.
+         *
+         * Note that this tracks running averages of create/bind time across all RecyclerViews
+         * (and, indirectly, Adapters) that use this pool.
+         *
+         * 1) This enables us to track average create and bind times across multiple adapters. Even
+         * though create (and especially bind) may behave differently for different Adapter
+         * subclasses, sharing the pool is a strong signal that they'll perform similarly, per type.
+         *
+         * 2) If {@link #willBindInTime(int, long, long)} returns false for one view, it will return
+         * false for all other views of its type for the same deadline. This prevents items
+         * constructed by {@link GapWorker} prefetch from being bound to a lower priority prefetch.
+         */
+        static class ScrapData {
+            ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
+            int mMaxScrap = DEFAULT_MAX_SCRAP;
+            long mCreateRunningAverageNs = 0;
+            long mBindRunningAverageNs = 0;
+        }
+        SparseArray<ScrapData> mScrap = new SparseArray<>();
+
+        private int mAttachCount = 0;
+
+        public void clear() {
+            for (int i = 0; i < mScrap.size(); i++) {
+                ScrapData data = mScrap.valueAt(i);
+                data.mScrapHeap.clear();
+            }
+        }
+
+        public void setMaxRecycledViews(int viewType, int max) {
+            ScrapData scrapData = getScrapDataForType(viewType);
+            scrapData.mMaxScrap = max;
+            final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
+            if (scrapHeap != null) {
+                while (scrapHeap.size() > max) {
+                    scrapHeap.remove(scrapHeap.size() - 1);
+                }
+            }
+        }
+
+        /**
+         * Returns the current number of Views held by the RecycledViewPool of the given view type.
+         */
+        public int getRecycledViewCount(int viewType) {
+            return getScrapDataForType(viewType).mScrapHeap.size();
+        }
+
+        public ViewHolder getRecycledView(int viewType) {
+            final ScrapData scrapData = mScrap.get(viewType);
+            if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
+                final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
+                return scrapHeap.remove(scrapHeap.size() - 1);
+            }
+            return null;
+        }
+
+        int size() {
+            int count = 0;
+            for (int i = 0; i < mScrap.size(); i++) {
+                ArrayList<ViewHolder> viewHolders = mScrap.valueAt(i).mScrapHeap;
+                if (viewHolders != null) {
+                    count += viewHolders.size();
+                }
+            }
+            return count;
+        }
+
+        public void putRecycledView(ViewHolder scrap) {
+            final int viewType = scrap.getItemViewType();
+            final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;
+            if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
+                return;
+            }
+            if (DEBUG && scrapHeap.contains(scrap)) {
+                throw new IllegalArgumentException("this scrap item already exists");
+            }
+            scrap.resetInternal();
+            scrapHeap.add(scrap);
+        }
+
+        long runningAverage(long oldAverage, long newValue) {
+            if (oldAverage == 0) {
+                return newValue;
+            }
+            return (oldAverage / 4 * 3) + (newValue / 4);
+        }
+
+        void factorInCreateTime(int viewType, long createTimeNs) {
+            ScrapData scrapData = getScrapDataForType(viewType);
+            scrapData.mCreateRunningAverageNs = runningAverage(
+                    scrapData.mCreateRunningAverageNs, createTimeNs);
+        }
+
+        void factorInBindTime(int viewType, long bindTimeNs) {
+            ScrapData scrapData = getScrapDataForType(viewType);
+            scrapData.mBindRunningAverageNs = runningAverage(
+                    scrapData.mBindRunningAverageNs, bindTimeNs);
+        }
+
+        boolean willCreateInTime(int viewType, long approxCurrentNs, long deadlineNs) {
+            long expectedDurationNs = getScrapDataForType(viewType).mCreateRunningAverageNs;
+            return expectedDurationNs == 0 || (approxCurrentNs + expectedDurationNs < deadlineNs);
+        }
+
+        boolean willBindInTime(int viewType, long approxCurrentNs, long deadlineNs) {
+            long expectedDurationNs = getScrapDataForType(viewType).mBindRunningAverageNs;
+            return expectedDurationNs == 0 || (approxCurrentNs + expectedDurationNs < deadlineNs);
+        }
+
+        void attach(Adapter adapter) {
+            mAttachCount++;
+        }
+
+        void detach() {
+            mAttachCount--;
+        }
+
+
+        /**
+         * Detaches the old adapter and attaches the new one.
+         * <p>
+         * RecycledViewPool will clear its cache if it has only one adapter attached and the new
+         * adapter uses a different ViewHolder than the oldAdapter.
+         *
+         * @param oldAdapter The previous adapter instance. Will be detached.
+         * @param newAdapter The new adapter instance. Will be attached.
+         * @param compatibleWithPrevious True if both oldAdapter and newAdapter are using the same
+         *                               ViewHolder and view types.
+         */
+        void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter,
+                boolean compatibleWithPrevious) {
+            if (oldAdapter != null) {
+                detach();
+            }
+            if (!compatibleWithPrevious && mAttachCount == 0) {
+                clear();
+            }
+            if (newAdapter != null) {
+                attach(newAdapter);
+            }
+        }
+
+        private ScrapData getScrapDataForType(int viewType) {
+            ScrapData scrapData = mScrap.get(viewType);
+            if (scrapData == null) {
+                scrapData = new ScrapData();
+                mScrap.put(viewType, scrapData);
+            }
+            return scrapData;
+        }
+    }
+
+    /**
+     * Utility method for finding an internal RecyclerView, if present
+     */
+    @Nullable
+    static RecyclerView findNestedRecyclerView(@NonNull View view) {
+        if (!(view instanceof ViewGroup)) {
+            return null;
+        }
+        if (view instanceof RecyclerView) {
+            return (RecyclerView) view;
+        }
+        final ViewGroup parent = (ViewGroup) view;
+        final int count = parent.getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = parent.getChildAt(i);
+            final RecyclerView descendant = findNestedRecyclerView(child);
+            if (descendant != null) {
+                return descendant;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Utility method for clearing holder's internal RecyclerView, if present
+     */
+    static void clearNestedRecyclerViewIfNotNested(@NonNull ViewHolder holder) {
+        if (holder.mNestedRecyclerView != null) {
+            View item = holder.mNestedRecyclerView.get();
+            while (item != null) {
+                if (item == holder.itemView) {
+                    return; // match found, don't need to clear
+                }
+
+                ViewParent parent = item.getParent();
+                if (parent instanceof View) {
+                    item = (View) parent;
+                } else {
+                    item = null;
+                }
+            }
+            holder.mNestedRecyclerView = null; // not nested
+        }
+    }
+
+    /**
+     * Time base for deadline-aware work scheduling. Overridable for testing.
+     *
+     * Will return 0 to avoid cost of System.nanoTime where deadline-aware work scheduling
+     * isn't relevant.
+     */
+    long getNanoTime() {
+        if (ALLOW_THREAD_GAP_WORK) {
+            return System.nanoTime();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * A Recycler is responsible for managing scrapped or detached item views for reuse.
+     *
+     * <p>A "scrapped" view is a view that is still attached to its parent RecyclerView but
+     * that has been marked for removal or reuse.</p>
+     *
+     * <p>Typical use of a Recycler by a {@link LayoutManager} will be to obtain views for
+     * an adapter's data set representing the data at a given position or item ID.
+     * If the view to be reused is considered "dirty" the adapter will be asked to rebind it.
+     * If not, the view can be quickly reused by the LayoutManager with no further work.
+     * Clean views that have not {@link android.view.View#isLayoutRequested() requested layout}
+     * may be repositioned by a LayoutManager without remeasurement.</p>
+     */
+    public final class Recycler {
+        final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
+        ArrayList<ViewHolder> mChangedScrap = null;
+
+        final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
+
+        private final List<ViewHolder>
+                mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
+
+        private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
+        int mViewCacheMax = DEFAULT_CACHE_SIZE;
+
+        RecycledViewPool mRecyclerPool;
+
+        private ViewCacheExtension mViewCacheExtension;
+
+        static final int DEFAULT_CACHE_SIZE = 2;
+
+        /**
+         * Clear scrap views out of this recycler. Detached views contained within a
+         * recycled view pool will remain.
+         */
+        public void clear() {
+            mAttachedScrap.clear();
+            recycleAndClearCachedViews();
+        }
+
+        /**
+         * Set the maximum number of detached, valid views we should retain for later use.
+         *
+         * @param viewCount Number of views to keep before sending views to the shared pool
+         */
+        public void setViewCacheSize(int viewCount) {
+            mRequestedCacheMax = viewCount;
+            updateViewCacheSize();
+        }
+
+        void updateViewCacheSize() {
+            int extraCache = mLayout != null ? mLayout.mPrefetchMaxCountObserved : 0;
+            mViewCacheMax = mRequestedCacheMax + extraCache;
+
+            // first, try the views that can be recycled
+            for (int i = mCachedViews.size() - 1;
+                    i >= 0 && mCachedViews.size() > mViewCacheMax; i--) {
+                recycleCachedViewAt(i);
+            }
+        }
+
+        /**
+         * Returns an unmodifiable list of ViewHolders that are currently in the scrap list.
+         *
+         * @return List of ViewHolders in the scrap list.
+         */
+        public List<ViewHolder> getScrapList() {
+            return mUnmodifiableAttachedScrap;
+        }
+
+        /**
+         * Helper method for getViewForPosition.
+         * <p>
+         * Checks whether a given view holder can be used for the provided position.
+         *
+         * @param holder ViewHolder
+         * @return true if ViewHolder matches the provided position, false otherwise
+         */
+        boolean validateViewHolderForOffsetPosition(ViewHolder holder) {
+            // if it is a removed holder, nothing to verify since we cannot ask adapter anymore
+            // if it is not removed, verify the type and id.
+            if (holder.isRemoved()) {
+                if (DEBUG && !mState.isPreLayout()) {
+                    throw new IllegalStateException("should not receive a removed view unless it"
+                            + " is pre layout");
+                }
+                return mState.isPreLayout();
+            }
+            if (holder.mPosition < 0 || holder.mPosition >= mAdapter.getItemCount()) {
+                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid view holder "
+                        + "adapter position" + holder);
+            }
+            if (!mState.isPreLayout()) {
+                // don't check type if it is pre-layout.
+                final int type = mAdapter.getItemViewType(holder.mPosition);
+                if (type != holder.getItemViewType()) {
+                    return false;
+                }
+            }
+            if (mAdapter.hasStableIds()) {
+                return holder.getItemId() == mAdapter.getItemId(holder.mPosition);
+            }
+            return true;
+        }
+
+        /**
+         * Attempts to bind view, and account for relevant timing information. If
+         * deadlineNs != FOREVER_NS, this method may fail to bind, and return false.
+         *
+         * @param holder Holder to be bound.
+         * @param offsetPosition Position of item to be bound.
+         * @param position Pre-layout position of item to be bound.
+         * @param deadlineNs Time, relative to getNanoTime(), by which bind/create work should
+         *                   complete. If FOREVER_NS is passed, this method will not fail to
+         *                   bind the holder.
+         * @return
+         */
+        private boolean tryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition,
+                int position, long deadlineNs) {
+            holder.mOwnerRecyclerView = RecyclerView.this;
+            final int viewType = holder.getItemViewType();
+            long startBindNs = getNanoTime();
+            if (deadlineNs != FOREVER_NS
+                    && !mRecyclerPool.willBindInTime(viewType, startBindNs, deadlineNs)) {
+                // abort - we have a deadline we can't meet
+                return false;
+            }
+            mAdapter.bindViewHolder(holder, offsetPosition);
+            long endBindNs = getNanoTime();
+            mRecyclerPool.factorInBindTime(holder.getItemViewType(), endBindNs - startBindNs);
+            attachAccessibilityDelegate(holder.itemView);
+            if (mState.isPreLayout()) {
+                holder.mPreLayoutPosition = position;
+            }
+            return true;
+        }
+
+        /**
+         * Binds the given View to the position. The View can be a View previously retrieved via
+         * {@link #getViewForPosition(int)} or created by
+         * {@link Adapter#onCreateViewHolder(ViewGroup, int)}.
+         * <p>
+         * Generally, a LayoutManager should acquire its views via {@link #getViewForPosition(int)}
+         * and let the RecyclerView handle caching. This is a helper method for LayoutManager who
+         * wants to handle its own recycling logic.
+         * <p>
+         * Note that, {@link #getViewForPosition(int)} already binds the View to the position so
+         * you don't need to call this method unless you want to bind this View to another position.
+         *
+         * @param view The view to update.
+         * @param position The position of the item to bind to this View.
+         */
+        public void bindViewToPosition(View view, int position) {
+            ViewHolder holder = getChildViewHolderInt(view);
+            if (holder == null) {
+                throw new IllegalArgumentException("The view does not have a ViewHolder. You cannot"
+                        + " pass arbitrary views to this method, they should be created by the "
+                        + "Adapter");
+            }
+            final int offsetPosition = mAdapterHelper.findPositionOffset(position);
+            if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
+                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
+                        + "position " + position + "(offset:" + offsetPosition + ")."
+                        + "state:" + mState.getItemCount());
+            }
+            tryBindViewHolderByDeadline(holder, offsetPosition, position, FOREVER_NS);
+
+            final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+            final LayoutParams rvLayoutParams;
+            if (lp == null) {
+                rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
+                holder.itemView.setLayoutParams(rvLayoutParams);
+            } else if (!checkLayoutParams(lp)) {
+                rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
+                holder.itemView.setLayoutParams(rvLayoutParams);
+            } else {
+                rvLayoutParams = (LayoutParams) lp;
+            }
+
+            rvLayoutParams.mInsetsDirty = true;
+            rvLayoutParams.mViewHolder = holder;
+            rvLayoutParams.mPendingInvalidate = holder.itemView.getParent() == null;
+        }
+
+        /**
+         * RecyclerView provides artificial position range (item count) in pre-layout state and
+         * automatically maps these positions to {@link Adapter} positions when
+         * {@link #getViewForPosition(int)} or {@link #bindViewToPosition(View, int)} is called.
+         * <p>
+         * Usually, LayoutManager does not need to worry about this. However, in some cases, your
+         * LayoutManager may need to call some custom component with item positions in which
+         * case you need the actual adapter position instead of the pre layout position. You
+         * can use this method to convert a pre-layout position to adapter (post layout) position.
+         * <p>
+         * Note that if the provided position belongs to a deleted ViewHolder, this method will
+         * return -1.
+         * <p>
+         * Calling this method in post-layout state returns the same value back.
+         *
+         * @param position The pre-layout position to convert. Must be greater or equal to 0 and
+         *                 less than {@link State#getItemCount()}.
+         */
+        public int convertPreLayoutPositionToPostLayout(int position) {
+            if (position < 0 || position >= mState.getItemCount()) {
+                throw new IndexOutOfBoundsException("invalid position " + position + ". State "
+                        + "item count is " + mState.getItemCount());
+            }
+            if (!mState.isPreLayout()) {
+                return position;
+            }
+            return mAdapterHelper.findPositionOffset(position);
+        }
+
+        /**
+         * Obtain a view initialized for the given position.
+         *
+         * This method should be used by {@link LayoutManager} implementations to obtain
+         * views to represent data from an {@link Adapter}.
+         * <p>
+         * The Recycler may reuse a scrap or detached view from a shared pool if one is
+         * available for the correct view type. If the adapter has not indicated that the
+         * data at the given position has changed, the Recycler will attempt to hand back
+         * a scrap view that was previously initialized for that data without rebinding.
+         *
+         * @param position Position to obtain a view for
+         * @return A view representing the data at <code>position</code> from <code>adapter</code>
+         */
+        public View getViewForPosition(int position) {
+            return getViewForPosition(position, false);
+        }
+
+        View getViewForPosition(int position, boolean dryRun) {
+            return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView;
+        }
+
+        /**
+         * Attempts to get the ViewHolder for the given position, either from the Recycler scrap,
+         * cache, the RecycledViewPool, or creating it directly.
+         * <p>
+         * If a deadlineNs other than {@link #FOREVER_NS} is passed, this method early return
+         * rather than constructing or binding a ViewHolder if it doesn't think it has time.
+         * If a ViewHolder must be constructed and not enough time remains, null is returned. If a
+         * ViewHolder is aquired and must be bound but not enough time remains, an unbound holder is
+         * returned. Use {@link ViewHolder#isBound()} on the returned object to check for this.
+         *
+         * @param position Position of ViewHolder to be returned.
+         * @param dryRun True if the ViewHolder should not be removed from scrap/cache/
+         * @param deadlineNs Time, relative to getNanoTime(), by which bind/create work should
+         *                   complete. If FOREVER_NS is passed, this method will not fail to
+         *                   create/bind the holder if needed.
+         *
+         * @return ViewHolder for requested position
+         */
+        @Nullable
+        ViewHolder tryGetViewHolderForPositionByDeadline(int position,
+                boolean dryRun, long deadlineNs) {
+            if (position < 0 || position >= mState.getItemCount()) {
+                throw new IndexOutOfBoundsException("Invalid item position " + position
+                        + "(" + position + "). Item count:" + mState.getItemCount());
+            }
+            boolean fromScrapOrHiddenOrCache = false;
+            ViewHolder holder = null;
+            // 0) If there is a changed scrap, try to find from there
+            if (mState.isPreLayout()) {
+                holder = getChangedScrapViewForPosition(position);
+                fromScrapOrHiddenOrCache = holder != null;
+            }
+            // 1) Find by position from scrap/hidden list/cache
+            if (holder == null) {
+                holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
+                if (holder != null) {
+                    if (!validateViewHolderForOffsetPosition(holder)) {
+                        // recycle holder (and unscrap if relevant) since it can't be used
+                        if (!dryRun) {
+                            // we would like to recycle this but need to make sure it is not used by
+                            // animation logic etc.
+                            holder.addFlags(ViewHolder.FLAG_INVALID);
+                            if (holder.isScrap()) {
+                                removeDetachedView(holder.itemView, false);
+                                holder.unScrap();
+                            } else if (holder.wasReturnedFromScrap()) {
+                                holder.clearReturnedFromScrapFlag();
+                            }
+                            recycleViewHolderInternal(holder);
+                        }
+                        holder = null;
+                    } else {
+                        fromScrapOrHiddenOrCache = true;
+                    }
+                }
+            }
+            if (holder == null) {
+                final int offsetPosition = mAdapterHelper.findPositionOffset(position);
+                if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) {
+                    throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item "
+                            + "position " + position + "(offset:" + offsetPosition + ")."
+                            + "state:" + mState.getItemCount());
+                }
+
+                final int type = mAdapter.getItemViewType(offsetPosition);
+                // 2) Find from scrap/cache via stable ids, if exists
+                if (mAdapter.hasStableIds()) {
+                    holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
+                            type, dryRun);
+                    if (holder != null) {
+                        // update position
+                        holder.mPosition = offsetPosition;
+                        fromScrapOrHiddenOrCache = true;
+                    }
+                }
+                if (holder == null && mViewCacheExtension != null) {
+                    // We are NOT sending the offsetPosition because LayoutManager does not
+                    // know it.
+                    final View view = mViewCacheExtension
+                            .getViewForPositionAndType(this, position, type);
+                    if (view != null) {
+                        holder = getChildViewHolder(view);
+                        if (holder == null) {
+                            throw new IllegalArgumentException("getViewForPositionAndType returned"
+                                    + " a view which does not have a ViewHolder");
+                        } else if (holder.shouldIgnore()) {
+                            throw new IllegalArgumentException("getViewForPositionAndType returned"
+                                    + " a view that is ignored. You must call stopIgnoring before"
+                                    + " returning this view.");
+                        }
+                    }
+                }
+                if (holder == null) { // fallback to pool
+                    if (DEBUG) {
+                        Log.d(TAG, "tryGetViewHolderForPositionByDeadline("
+                                + position + ") fetching from shared pool");
+                    }
+                    holder = getRecycledViewPool().getRecycledView(type);
+                    if (holder != null) {
+                        holder.resetInternal();
+                        if (FORCE_INVALIDATE_DISPLAY_LIST) {
+                            invalidateDisplayListInt(holder);
+                        }
+                    }
+                }
+                if (holder == null) {
+                    long start = getNanoTime();
+                    if (deadlineNs != FOREVER_NS
+                            && !mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
+                        // abort - we have a deadline we can't meet
+                        return null;
+                    }
+                    holder = mAdapter.createViewHolder(RecyclerView.this, type);
+                    if (ALLOW_THREAD_GAP_WORK) {
+                        // only bother finding nested RV if prefetching
+                        RecyclerView innerView = findNestedRecyclerView(holder.itemView);
+                        if (innerView != null) {
+                            holder.mNestedRecyclerView = new WeakReference<>(innerView);
+                        }
+                    }
+
+                    long end = getNanoTime();
+                    mRecyclerPool.factorInCreateTime(type, end - start);
+                    if (DEBUG) {
+                        Log.d(TAG, "tryGetViewHolderForPositionByDeadline created new ViewHolder");
+                    }
+                }
+            }
+
+            // This is very ugly but the only place we can grab this information
+            // before the View is rebound and returned to the LayoutManager for post layout ops.
+            // We don't need this in pre-layout since the VH is not updated by the LM.
+            if (fromScrapOrHiddenOrCache && !mState.isPreLayout() && holder
+                    .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST)) {
+                holder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+                if (mState.mRunSimpleAnimations) {
+                    int changeFlags = ItemAnimator
+                            .buildAdapterChangeFlagsForAnimations(holder);
+                    changeFlags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT;
+                    final ItemHolderInfo info = mItemAnimator.recordPreLayoutInformation(mState,
+                            holder, changeFlags, holder.getUnmodifiedPayloads());
+                    recordAnimationInfoIfBouncedHiddenView(holder, info);
+                }
+            }
+
+            boolean bound = false;
+            if (mState.isPreLayout() && holder.isBound()) {
+                // do not update unless we absolutely have to.
+                holder.mPreLayoutPosition = position;
+            } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
+                if (DEBUG && holder.isRemoved()) {
+                    throw new IllegalStateException("Removed holder should be bound and it should"
+                            + " come here only in pre-layout. Holder: " + holder);
+                }
+                final int offsetPosition = mAdapterHelper.findPositionOffset(position);
+                bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
+            }
+
+            final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+            final LayoutParams rvLayoutParams;
+            if (lp == null) {
+                rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
+                holder.itemView.setLayoutParams(rvLayoutParams);
+            } else if (!checkLayoutParams(lp)) {
+                rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
+                holder.itemView.setLayoutParams(rvLayoutParams);
+            } else {
+                rvLayoutParams = (LayoutParams) lp;
+            }
+            rvLayoutParams.mViewHolder = holder;
+            rvLayoutParams.mPendingInvalidate = fromScrapOrHiddenOrCache && bound;
+            return holder;
+        }
+
+        private void attachAccessibilityDelegate(View itemView) {
+            if (isAccessibilityEnabled()) {
+                if (itemView.getImportantForAccessibility()
+                        == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+                    itemView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+                }
+
+                if (itemView.getAccessibilityDelegate() == null) {
+                    itemView.setAccessibilityDelegate(mAccessibilityDelegate.getItemDelegate());
+                }
+            }
+        }
+
+        private void invalidateDisplayListInt(ViewHolder holder) {
+            if (holder.itemView instanceof ViewGroup) {
+                invalidateDisplayListInt((ViewGroup) holder.itemView, false);
+            }
+        }
+
+        private void invalidateDisplayListInt(ViewGroup viewGroup, boolean invalidateThis) {
+            for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) {
+                final View view = viewGroup.getChildAt(i);
+                if (view instanceof ViewGroup) {
+                    invalidateDisplayListInt((ViewGroup) view, true);
+                }
+            }
+            if (!invalidateThis) {
+                return;
+            }
+            // we need to force it to become invisible
+            if (viewGroup.getVisibility() == View.INVISIBLE) {
+                viewGroup.setVisibility(View.VISIBLE);
+                viewGroup.setVisibility(View.INVISIBLE);
+            } else {
+                final int visibility = viewGroup.getVisibility();
+                viewGroup.setVisibility(View.INVISIBLE);
+                viewGroup.setVisibility(visibility);
+            }
+        }
+
+        /**
+         * Recycle a detached view. The specified view will be added to a pool of views
+         * for later rebinding and reuse.
+         *
+         * <p>A view must be fully detached (removed from parent) before it may be recycled. If the
+         * View is scrapped, it will be removed from scrap list.</p>
+         *
+         * @param view Removed view for recycling
+         * @see LayoutManager#removeAndRecycleView(View, Recycler)
+         */
+        public void recycleView(View view) {
+            // This public recycle method tries to make view recycle-able since layout manager
+            // intended to recycle this view (e.g. even if it is in scrap or change cache)
+            ViewHolder holder = getChildViewHolderInt(view);
+            if (holder.isTmpDetached()) {
+                removeDetachedView(view, false);
+            }
+            if (holder.isScrap()) {
+                holder.unScrap();
+            } else if (holder.wasReturnedFromScrap()) {
+                holder.clearReturnedFromScrapFlag();
+            }
+            recycleViewHolderInternal(holder);
+        }
+
+        /**
+         * Internally, use this method instead of {@link #recycleView(android.view.View)} to
+         * catch potential bugs.
+         * @param view
+         */
+        void recycleViewInternal(View view) {
+            recycleViewHolderInternal(getChildViewHolderInt(view));
+        }
+
+        void recycleAndClearCachedViews() {
+            final int count = mCachedViews.size();
+            for (int i = count - 1; i >= 0; i--) {
+                recycleCachedViewAt(i);
+            }
+            mCachedViews.clear();
+            if (ALLOW_THREAD_GAP_WORK) {
+                mPrefetchRegistry.clearPrefetchPositions();
+            }
+        }
+
+        /**
+         * Recycles a cached view and removes the view from the list. Views are added to cache
+         * if and only if they are recyclable, so this method does not check it again.
+         * <p>
+         * A small exception to this rule is when the view does not have an animator reference
+         * but transient state is true (due to animations created outside ItemAnimator). In that
+         * case, adapter may choose to recycle it. From RecyclerView's perspective, the view is
+         * still recyclable since Adapter wants to do so.
+         *
+         * @param cachedViewIndex The index of the view in cached views list
+         */
+        void recycleCachedViewAt(int cachedViewIndex) {
+            if (DEBUG) {
+                Log.d(TAG, "Recycling cached view at index " + cachedViewIndex);
+            }
+            ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);
+            if (DEBUG) {
+                Log.d(TAG, "CachedViewHolder to be recycled: " + viewHolder);
+            }
+            addViewHolderToRecycledViewPool(viewHolder, true);
+            mCachedViews.remove(cachedViewIndex);
+        }
+
+        /**
+         * internal implementation checks if view is scrapped or attached and throws an exception
+         * if so.
+         * Public version un-scraps before calling recycle.
+         */
+        void recycleViewHolderInternal(ViewHolder holder) {
+            if (holder.isScrap() || holder.itemView.getParent() != null) {
+                throw new IllegalArgumentException(
+                        "Scrapped or attached views may not be recycled. isScrap:"
+                                + holder.isScrap() + " isAttached:"
+                                + (holder.itemView.getParent() != null));
+            }
+
+            if (holder.isTmpDetached()) {
+                throw new IllegalArgumentException("Tmp detached view should be removed "
+                        + "from RecyclerView before it can be recycled: " + holder);
+            }
+
+            if (holder.shouldIgnore()) {
+                throw new IllegalArgumentException("Trying to recycle an ignored view holder. You"
+                        + " should first call stopIgnoringView(view) before calling recycle.");
+            }
+            //noinspection unchecked
+            final boolean transientStatePreventsRecycling = holder
+                    .doesTransientStatePreventRecycling();
+            final boolean forceRecycle = mAdapter != null
+                    && transientStatePreventsRecycling
+                    && mAdapter.onFailedToRecycleView(holder);
+            boolean cached = false;
+            boolean recycled = false;
+            if (DEBUG && mCachedViews.contains(holder)) {
+                throw new IllegalArgumentException("cached view received recycle internal? "
+                        + holder);
+            }
+            if (forceRecycle || holder.isRecyclable()) {
+                if (mViewCacheMax > 0
+                        && !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
+                                | ViewHolder.FLAG_REMOVED
+                                | ViewHolder.FLAG_UPDATE
+                                | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {
+                    // Retire oldest cached view
+                    int cachedViewSize = mCachedViews.size();
+                    if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
+                        recycleCachedViewAt(0);
+                        cachedViewSize--;
+                    }
+
+                    int targetCacheIndex = cachedViewSize;
+                    if (ALLOW_THREAD_GAP_WORK
+                            && cachedViewSize > 0
+                            && !mPrefetchRegistry.lastPrefetchIncludedPosition(holder.mPosition)) {
+                        // when adding the view, skip past most recently prefetched views
+                        int cacheIndex = cachedViewSize - 1;
+                        while (cacheIndex >= 0) {
+                            int cachedPos = mCachedViews.get(cacheIndex).mPosition;
+                            if (!mPrefetchRegistry.lastPrefetchIncludedPosition(cachedPos)) {
+                                break;
+                            }
+                            cacheIndex--;
+                        }
+                        targetCacheIndex = cacheIndex + 1;
+                    }
+                    mCachedViews.add(targetCacheIndex, holder);
+                    cached = true;
+                }
+                if (!cached) {
+                    addViewHolderToRecycledViewPool(holder, true);
+                    recycled = true;
+                }
+            } else {
+                // NOTE: A view can fail to be recycled when it is scrolled off while an animation
+                // runs. In this case, the item is eventually recycled by
+                // ItemAnimatorRestoreListener#onAnimationFinished.
+
+                // TODO: consider cancelling an animation when an item is removed scrollBy,
+                // to return it to the pool faster
+                if (DEBUG) {
+                    Log.d(TAG, "trying to recycle a non-recycleable holder. Hopefully, it will "
+                            + "re-visit here. We are still removing it from animation lists");
+                }
+            }
+            // even if the holder is not removed, we still call this method so that it is removed
+            // from view holder lists.
+            mViewInfoStore.removeViewHolder(holder);
+            if (!cached && !recycled && transientStatePreventsRecycling) {
+                holder.mOwnerRecyclerView = null;
+            }
+        }
+
+        /**
+         * Prepares the ViewHolder to be removed/recycled, and inserts it into the RecycledViewPool.
+         *
+         * Pass false to dispatchRecycled for views that have not been bound.
+         *
+         * @param holder Holder to be added to the pool.
+         * @param dispatchRecycled True to dispatch View recycled callbacks.
+         */
+        void addViewHolderToRecycledViewPool(ViewHolder holder, boolean dispatchRecycled) {
+            clearNestedRecyclerViewIfNotNested(holder);
+            holder.itemView.setAccessibilityDelegate(null);
+            if (dispatchRecycled) {
+                dispatchViewRecycled(holder);
+            }
+            holder.mOwnerRecyclerView = null;
+            getRecycledViewPool().putRecycledView(holder);
+        }
+
+        /**
+         * Used as a fast path for unscrapping and recycling a view during a bulk operation.
+         * The caller must call {@link #clearScrap()} when it's done to update the recycler's
+         * internal bookkeeping.
+         */
+        void quickRecycleScrapView(View view) {
+            final ViewHolder holder = getChildViewHolderInt(view);
+            holder.mScrapContainer = null;
+            holder.mInChangeScrap = false;
+            holder.clearReturnedFromScrapFlag();
+            recycleViewHolderInternal(holder);
+        }
+
+        /**
+         * Mark an attached view as scrap.
+         *
+         * <p>"Scrap" views are still attached to their parent RecyclerView but are eligible
+         * for rebinding and reuse. Requests for a view for a given position may return a
+         * reused or rebound scrap view instance.</p>
+         *
+         * @param view View to scrap
+         */
+        void scrapView(View view) {
+            final ViewHolder holder = getChildViewHolderInt(view);
+            if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
+                    || !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
+                if (holder.isInvalid() && !holder.isRemoved() && !mAdapter.hasStableIds()) {
+                    throw new IllegalArgumentException("Called scrap view with an invalid view."
+                            + " Invalid views cannot be reused from scrap, they should rebound from"
+                            + " recycler pool.");
+                }
+                holder.setScrapContainer(this, false);
+                mAttachedScrap.add(holder);
+            } else {
+                if (mChangedScrap == null) {
+                    mChangedScrap = new ArrayList<ViewHolder>();
+                }
+                holder.setScrapContainer(this, true);
+                mChangedScrap.add(holder);
+            }
+        }
+
+        /**
+         * Remove a previously scrapped view from the pool of eligible scrap.
+         *
+         * <p>This view will no longer be eligible for reuse until re-scrapped or
+         * until it is explicitly removed and recycled.</p>
+         */
+        void unscrapView(ViewHolder holder) {
+            if (holder.mInChangeScrap) {
+                mChangedScrap.remove(holder);
+            } else {
+                mAttachedScrap.remove(holder);
+            }
+            holder.mScrapContainer = null;
+            holder.mInChangeScrap = false;
+            holder.clearReturnedFromScrapFlag();
+        }
+
+        int getScrapCount() {
+            return mAttachedScrap.size();
+        }
+
+        View getScrapViewAt(int index) {
+            return mAttachedScrap.get(index).itemView;
+        }
+
+        void clearScrap() {
+            mAttachedScrap.clear();
+            if (mChangedScrap != null) {
+                mChangedScrap.clear();
+            }
+        }
+
+        ViewHolder getChangedScrapViewForPosition(int position) {
+            // If pre-layout, check the changed scrap for an exact match.
+            final int changedScrapSize;
+            if (mChangedScrap == null || (changedScrapSize = mChangedScrap.size()) == 0) {
+                return null;
+            }
+            // find by position
+            for (int i = 0; i < changedScrapSize; i++) {
+                final ViewHolder holder = mChangedScrap.get(i);
+                if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position) {
+                    holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
+                    return holder;
+                }
+            }
+            // find by id
+            if (mAdapter.hasStableIds()) {
+                final int offsetPosition = mAdapterHelper.findPositionOffset(position);
+                if (offsetPosition > 0 && offsetPosition < mAdapter.getItemCount()) {
+                    final long id = mAdapter.getItemId(offsetPosition);
+                    for (int i = 0; i < changedScrapSize; i++) {
+                        final ViewHolder holder = mChangedScrap.get(i);
+                        if (!holder.wasReturnedFromScrap() && holder.getItemId() == id) {
+                            holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
+                            return holder;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Returns a view for the position either from attach scrap, hidden children, or cache.
+         *
+         * @param position Item position
+         * @param dryRun  Does a dry run, finds the ViewHolder but does not remove
+         * @return a ViewHolder that can be re-used for this position.
+         */
+        ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {
+            final int scrapCount = mAttachedScrap.size();
+
+            // Try first for an exact, non-invalid match from scrap.
+            for (int i = 0; i < scrapCount; i++) {
+                final ViewHolder holder = mAttachedScrap.get(i);
+                if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position
+                        && !holder.isInvalid() && (mState.mInPreLayout || !holder.isRemoved())) {
+                    holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
+                    return holder;
+                }
+            }
+
+            if (!dryRun) {
+                View view = mChildHelper.findHiddenNonRemovedView(position);
+                if (view != null) {
+                    // This View is good to be used. We just need to unhide, detach and move to the
+                    // scrap list.
+                    final ViewHolder vh = getChildViewHolderInt(view);
+                    mChildHelper.unhide(view);
+                    int layoutIndex = mChildHelper.indexOfChild(view);
+                    if (layoutIndex == RecyclerView.NO_POSITION) {
+                        throw new IllegalStateException("layout index should not be -1 after "
+                                + "unhiding a view:" + vh);
+                    }
+                    mChildHelper.detachViewFromParent(layoutIndex);
+                    scrapView(view);
+                    vh.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP
+                            | ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);
+                    return vh;
+                }
+            }
+
+            // Search in our first-level recycled view cache.
+            final int cacheSize = mCachedViews.size();
+            for (int i = 0; i < cacheSize; i++) {
+                final ViewHolder holder = mCachedViews.get(i);
+                // invalid view holders may be in cache if adapter has stable ids as they can be
+                // retrieved via getScrapOrCachedViewForId
+                if (!holder.isInvalid() && holder.getLayoutPosition() == position) {
+                    if (!dryRun) {
+                        mCachedViews.remove(i);
+                    }
+                    if (DEBUG) {
+                        Log.d(TAG, "getScrapOrHiddenOrCachedHolderForPosition(" + position
+                                + ") found match in cache: " + holder);
+                    }
+                    return holder;
+                }
+            }
+            return null;
+        }
+
+        ViewHolder getScrapOrCachedViewForId(long id, int type, boolean dryRun) {
+            // Look in our attached views first
+            final int count = mAttachedScrap.size();
+            for (int i = count - 1; i >= 0; i--) {
+                final ViewHolder holder = mAttachedScrap.get(i);
+                if (holder.getItemId() == id && !holder.wasReturnedFromScrap()) {
+                    if (type == holder.getItemViewType()) {
+                        holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
+                        if (holder.isRemoved()) {
+                            // this might be valid in two cases:
+                            // > item is removed but we are in pre-layout pass
+                            // >> do nothing. return as is. make sure we don't rebind
+                            // > item is removed then added to another position and we are in
+                            // post layout.
+                            // >> remove removed and invalid flags, add update flag to rebind
+                            // because item was invisible to us and we don't know what happened in
+                            // between.
+                            if (!mState.isPreLayout()) {
+                                holder.setFlags(ViewHolder.FLAG_UPDATE, ViewHolder.FLAG_UPDATE
+                                        | ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED);
+                            }
+                        }
+                        return holder;
+                    } else if (!dryRun) {
+                        // if we are running animations, it is actually better to keep it in scrap
+                        // but this would force layout manager to lay it out which would be bad.
+                        // Recycle this scrap. Type mismatch.
+                        mAttachedScrap.remove(i);
+                        removeDetachedView(holder.itemView, false);
+                        quickRecycleScrapView(holder.itemView);
+                    }
+                }
+            }
+
+            // Search the first-level cache
+            final int cacheSize = mCachedViews.size();
+            for (int i = cacheSize - 1; i >= 0; i--) {
+                final ViewHolder holder = mCachedViews.get(i);
+                if (holder.getItemId() == id) {
+                    if (type == holder.getItemViewType()) {
+                        if (!dryRun) {
+                            mCachedViews.remove(i);
+                        }
+                        return holder;
+                    } else if (!dryRun) {
+                        recycleCachedViewAt(i);
+                        return null;
+                    }
+                }
+            }
+            return null;
+        }
+
+        void dispatchViewRecycled(ViewHolder holder) {
+            if (mRecyclerListener != null) {
+                mRecyclerListener.onViewRecycled(holder);
+            }
+            if (mAdapter != null) {
+                mAdapter.onViewRecycled(holder);
+            }
+            if (mState != null) {
+                mViewInfoStore.removeViewHolder(holder);
+            }
+            if (DEBUG) Log.d(TAG, "dispatchViewRecycled: " + holder);
+        }
+
+        void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter,
+                boolean compatibleWithPrevious) {
+            clear();
+            getRecycledViewPool().onAdapterChanged(oldAdapter, newAdapter, compatibleWithPrevious);
+        }
+
+        void offsetPositionRecordsForMove(int from, int to) {
+            final int start, end, inBetweenOffset;
+            if (from < to) {
+                start = from;
+                end = to;
+                inBetweenOffset = -1;
+            } else {
+                start = to;
+                end = from;
+                inBetweenOffset = 1;
+            }
+            final int cachedCount = mCachedViews.size();
+            for (int i = 0; i < cachedCount; i++) {
+                final ViewHolder holder = mCachedViews.get(i);
+                if (holder == null || holder.mPosition < start || holder.mPosition > end) {
+                    continue;
+                }
+                if (holder.mPosition == from) {
+                    holder.offsetPosition(to - from, false);
+                } else {
+                    holder.offsetPosition(inBetweenOffset, false);
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "offsetPositionRecordsForMove cached child " + i + " holder "
+                            + holder);
+                }
+            }
+        }
+
+        void offsetPositionRecordsForInsert(int insertedAt, int count) {
+            final int cachedCount = mCachedViews.size();
+            for (int i = 0; i < cachedCount; i++) {
+                final ViewHolder holder = mCachedViews.get(i);
+                if (holder != null && holder.mPosition >= insertedAt) {
+                    if (DEBUG) {
+                        Log.d(TAG, "offsetPositionRecordsForInsert cached " + i + " holder "
+                                + holder + " now at position " + (holder.mPosition + count));
+                    }
+                    holder.offsetPosition(count, true);
+                }
+            }
+        }
+
+        /**
+         * @param removedFrom Remove start index
+         * @param count Remove count
+         * @param applyToPreLayout If true, changes will affect ViewHolder's pre-layout position, if
+         *                         false, they'll be applied before the second layout pass
+         */
+        void offsetPositionRecordsForRemove(int removedFrom, int count, boolean applyToPreLayout) {
+            final int removedEnd = removedFrom + count;
+            final int cachedCount = mCachedViews.size();
+            for (int i = cachedCount - 1; i >= 0; i--) {
+                final ViewHolder holder = mCachedViews.get(i);
+                if (holder != null) {
+                    if (holder.mPosition >= removedEnd) {
+                        if (DEBUG) {
+                            Log.d(TAG, "offsetPositionRecordsForRemove cached " + i
+                                    + " holder " + holder + " now at position "
+                                    + (holder.mPosition - count));
+                        }
+                        holder.offsetPosition(-count, applyToPreLayout);
+                    } else if (holder.mPosition >= removedFrom) {
+                        // Item for this view was removed. Dump it from the cache.
+                        holder.addFlags(ViewHolder.FLAG_REMOVED);
+                        recycleCachedViewAt(i);
+                    }
+                }
+            }
+        }
+
+        void setViewCacheExtension(ViewCacheExtension extension) {
+            mViewCacheExtension = extension;
+        }
+
+        void setRecycledViewPool(RecycledViewPool pool) {
+            if (mRecyclerPool != null) {
+                mRecyclerPool.detach();
+            }
+            mRecyclerPool = pool;
+            if (pool != null) {
+                mRecyclerPool.attach(getAdapter());
+            }
+        }
+
+        RecycledViewPool getRecycledViewPool() {
+            if (mRecyclerPool == null) {
+                mRecyclerPool = new RecycledViewPool();
+            }
+            return mRecyclerPool;
+        }
+
+        void viewRangeUpdate(int positionStart, int itemCount) {
+            final int positionEnd = positionStart + itemCount;
+            final int cachedCount = mCachedViews.size();
+            for (int i = cachedCount - 1; i >= 0; i--) {
+                final ViewHolder holder = mCachedViews.get(i);
+                if (holder == null) {
+                    continue;
+                }
+
+                final int pos = holder.getLayoutPosition();
+                if (pos >= positionStart && pos < positionEnd) {
+                    holder.addFlags(ViewHolder.FLAG_UPDATE);
+                    recycleCachedViewAt(i);
+                    // cached views should not be flagged as changed because this will cause them
+                    // to animate when they are returned from cache.
+                }
+            }
+        }
+
+        void setAdapterPositionsAsUnknown() {
+            final int cachedCount = mCachedViews.size();
+            for (int i = 0; i < cachedCount; i++) {
+                final ViewHolder holder = mCachedViews.get(i);
+                if (holder != null) {
+                    holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
+                }
+            }
+        }
+
+        void markKnownViewsInvalid() {
+            if (mAdapter != null && mAdapter.hasStableIds()) {
+                final int cachedCount = mCachedViews.size();
+                for (int i = 0; i < cachedCount; i++) {
+                    final ViewHolder holder = mCachedViews.get(i);
+                    if (holder != null) {
+                        holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);
+                        holder.addChangePayload(null);
+                    }
+                }
+            } else {
+                // we cannot re-use cached views in this case. Recycle them all
+                recycleAndClearCachedViews();
+            }
+        }
+
+        void clearOldPositions() {
+            final int cachedCount = mCachedViews.size();
+            for (int i = 0; i < cachedCount; i++) {
+                final ViewHolder holder = mCachedViews.get(i);
+                holder.clearOldPosition();
+            }
+            final int scrapCount = mAttachedScrap.size();
+            for (int i = 0; i < scrapCount; i++) {
+                mAttachedScrap.get(i).clearOldPosition();
+            }
+            if (mChangedScrap != null) {
+                final int changedScrapCount = mChangedScrap.size();
+                for (int i = 0; i < changedScrapCount; i++) {
+                    mChangedScrap.get(i).clearOldPosition();
+                }
+            }
+        }
+
+        void markItemDecorInsetsDirty() {
+            final int cachedCount = mCachedViews.size();
+            for (int i = 0; i < cachedCount; i++) {
+                final ViewHolder holder = mCachedViews.get(i);
+                LayoutParams layoutParams = (LayoutParams) holder.itemView.getLayoutParams();
+                if (layoutParams != null) {
+                    layoutParams.mInsetsDirty = true;
+                }
+            }
+        }
+    }
+
+    /**
+     * ViewCacheExtension is a helper class to provide an additional layer of view caching that can
+     * be controlled by the developer.
+     * <p>
+     * When {@link Recycler#getViewForPosition(int)} is called, Recycler checks attached scrap and
+     * first level cache to find a matching View. If it cannot find a suitable View, Recycler will
+     * call the {@link #getViewForPositionAndType(Recycler, int, int)} before checking
+     * {@link RecycledViewPool}.
+     * <p>
+     * Note that, Recycler never sends Views to this method to be cached. It is developers
+     * responsibility to decide whether they want to keep their Views in this custom cache or let
+     * the default recycling policy handle it.
+     */
+    public abstract static class ViewCacheExtension {
+
+        /**
+         * Returns a View that can be binded to the given Adapter position.
+         * <p>
+         * This method should <b>not</b> create a new View. Instead, it is expected to return
+         * an already created View that can be re-used for the given type and position.
+         * If the View is marked as ignored, it should first call
+         * {@link LayoutManager#stopIgnoringView(View)} before returning the View.
+         * <p>
+         * RecyclerView will re-bind the returned View to the position if necessary.
+         *
+         * @param recycler The Recycler that can be used to bind the View
+         * @param position The adapter position
+         * @param type     The type of the View, defined by adapter
+         * @return A View that is bound to the given position or NULL if there is no View to re-use
+         * @see LayoutManager#ignoreView(View)
+         */
+        public abstract View getViewForPositionAndType(Recycler recycler, int position, int type);
+    }
+
+    /**
+     * Base class for an Adapter
+     *
+     * <p>Adapters provide a binding from an app-specific data set to views that are displayed
+     * within a {@link RecyclerView}.</p>
+     *
+     * @param <VH> A class that extends ViewHolder that will be used by the adapter.
+     */
+    public abstract static class Adapter<VH extends ViewHolder> {
+        private final AdapterDataObservable mObservable = new AdapterDataObservable();
+        private boolean mHasStableIds = false;
+
+        /**
+         * Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent
+         * an item.
+         * <p>
+         * This new ViewHolder should be constructed with a new View that can represent the items
+         * of the given type. You can either create a new View manually or inflate it from an XML
+         * layout file.
+         * <p>
+         * The new ViewHolder will be used to display items of the adapter using
+         * {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display
+         * different items in the data set, it is a good idea to cache references to sub views of
+         * the View to avoid unnecessary {@link View#findViewById(int)} calls.
+         *
+         * @param parent The ViewGroup into which the new View will be added after it is bound to
+         *               an adapter position.
+         * @param viewType The view type of the new View.
+         *
+         * @return A new ViewHolder that holds a View of the given view type.
+         * @see #getItemViewType(int)
+         * @see #onBindViewHolder(ViewHolder, int)
+         */
+        public abstract VH onCreateViewHolder(ViewGroup parent, int viewType);
+
+        /**
+         * Called by RecyclerView to display the data at the specified position. This method should
+         * update the contents of the {@link ViewHolder#itemView} to reflect the item at the given
+         * position.
+         * <p>
+         * Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method
+         * again if the position of the item changes in the data set unless the item itself is
+         * invalidated or the new position cannot be determined. For this reason, you should only
+         * use the <code>position</code> parameter while acquiring the related data item inside
+         * this method and should not keep a copy of it. If you need the position of an item later
+         * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will
+         * have the updated adapter position.
+         *
+         * Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can
+         * handle efficient partial bind.
+         *
+         * @param holder The ViewHolder which should be updated to represent the contents of the
+         *        item at the given position in the data set.
+         * @param position The position of the item within the adapter's data set.
+         */
+        public abstract void onBindViewHolder(VH holder, int position);
+
+        /**
+         * Called by RecyclerView to display the data at the specified position. This method
+         * should update the contents of the {@link ViewHolder#itemView} to reflect the item at
+         * the given position.
+         * <p>
+         * Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method
+         * again if the position of the item changes in the data set unless the item itself is
+         * invalidated or the new position cannot be determined. For this reason, you should only
+         * use the <code>position</code> parameter while acquiring the related data item inside
+         * this method and should not keep a copy of it. If you need the position of an item later
+         * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will
+         * have the updated adapter position.
+         * <p>
+         * Partial bind vs full bind:
+         * <p>
+         * The payloads parameter is a merge list from {@link #notifyItemChanged(int, Object)} or
+         * {@link #notifyItemRangeChanged(int, int, Object)}.  If the payloads list is not empty,
+         * the ViewHolder is currently bound to old data and Adapter may run an efficient partial
+         * update using the payload info.  If the payload is empty,  Adapter must run a full bind.
+         * Adapter should not assume that the payload passed in notify methods will be received by
+         * onBindViewHolder().  For example when the view is not attached to the screen, the
+         * payload in notifyItemChange() will be simply dropped.
+         *
+         * @param holder The ViewHolder which should be updated to represent the contents of the
+         *               item at the given position in the data set.
+         * @param position The position of the item within the adapter's data set.
+         * @param payloads A non-null list of merged payloads. Can be empty list if requires full
+         *                 update.
+         */
+        public void onBindViewHolder(VH holder, int position, List<Object> payloads) {
+            onBindViewHolder(holder, position);
+        }
+
+        /**
+         * This method calls {@link #onCreateViewHolder(ViewGroup, int)} to create a new
+         * {@link ViewHolder} and initializes some private fields to be used by RecyclerView.
+         *
+         * @see #onCreateViewHolder(ViewGroup, int)
+         */
+        public final VH createViewHolder(ViewGroup parent, int viewType) {
+            Trace.beginSection(TRACE_CREATE_VIEW_TAG);
+            final VH holder = onCreateViewHolder(parent, viewType);
+            holder.mItemViewType = viewType;
+            Trace.endSection();
+            return holder;
+        }
+
+        /**
+         * This method internally calls {@link #onBindViewHolder(ViewHolder, int)} to update the
+         * {@link ViewHolder} contents with the item at the given position and also sets up some
+         * private fields to be used by RecyclerView.
+         *
+         * @see #onBindViewHolder(ViewHolder, int)
+         */
+        public final void bindViewHolder(VH holder, int position) {
+            holder.mPosition = position;
+            if (hasStableIds()) {
+                holder.mItemId = getItemId(position);
+            }
+            holder.setFlags(ViewHolder.FLAG_BOUND,
+                    ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
+                            | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
+            Trace.beginSection(TRACE_BIND_VIEW_TAG);
+            onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());
+            holder.clearPayload();
+            final ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
+            if (layoutParams instanceof RecyclerView.LayoutParams) {
+                ((LayoutParams) layoutParams).mInsetsDirty = true;
+            }
+            Trace.endSection();
+        }
+
+        /**
+         * Return the view type of the item at <code>position</code> for the purposes
+         * of view recycling.
+         *
+         * <p>The default implementation of this method returns 0, making the assumption of
+         * a single view type for the adapter. Unlike ListView adapters, types need not
+         * be contiguous. Consider using id resources to uniquely identify item view types.
+         *
+         * @param position position to query
+         * @return integer value identifying the type of the view needed to represent the item at
+         *                 <code>position</code>. Type codes need not be contiguous.
+         */
+        public int getItemViewType(int position) {
+            return 0;
+        }
+
+        /**
+         * Indicates whether each item in the data set can be represented with a unique identifier
+         * of type {@link java.lang.Long}.
+         *
+         * @param hasStableIds Whether items in data set have unique identifiers or not.
+         * @see #hasStableIds()
+         * @see #getItemId(int)
+         */
+        public void setHasStableIds(boolean hasStableIds) {
+            if (hasObservers()) {
+                throw new IllegalStateException("Cannot change whether this adapter has "
+                        + "stable IDs while the adapter has registered observers.");
+            }
+            mHasStableIds = hasStableIds;
+        }
+
+        /**
+         * Return the stable ID for the item at <code>position</code>. If {@link #hasStableIds()}
+         * would return false this method should return {@link #NO_ID}. The default implementation
+         * of this method returns {@link #NO_ID}.
+         *
+         * @param position Adapter position to query
+         * @return the stable ID of the item at position
+         */
+        public long getItemId(int position) {
+            return NO_ID;
+        }
+
+        /**
+         * Returns the total number of items in the data set held by the adapter.
+         *
+         * @return The total number of items in this adapter.
+         */
+        public abstract int getItemCount();
+
+        /**
+         * Returns true if this adapter publishes a unique <code>long</code> value that can
+         * act as a key for the item at a given position in the data set. If that item is relocated
+         * in the data set, the ID returned for that item should be the same.
+         *
+         * @return true if this adapter's items have stable IDs
+         */
+        public final boolean hasStableIds() {
+            return mHasStableIds;
+        }
+
+        /**
+         * Called when a view created by this adapter has been recycled.
+         *
+         * <p>A view is recycled when a {@link LayoutManager} decides that it no longer
+         * needs to be attached to its parent {@link RecyclerView}. This can be because it has
+         * fallen out of visibility or a set of cached views represented by views still
+         * attached to the parent RecyclerView. If an item view has large or expensive data
+         * bound to it such as large bitmaps, this may be a good place to release those
+         * resources.</p>
+         * <p>
+         * RecyclerView calls this method right before clearing ViewHolder's internal data and
+         * sending it to RecycledViewPool. This way, if ViewHolder was holding valid information
+         * before being recycled, you can call {@link ViewHolder#getAdapterPosition()} to get
+         * its adapter position.
+         *
+         * @param holder The ViewHolder for the view being recycled
+         */
+        public void onViewRecycled(VH holder) {
+        }
+
+        /**
+         * Called by the RecyclerView if a ViewHolder created by this Adapter cannot be recycled
+         * due to its transient state. Upon receiving this callback, Adapter can clear the
+         * animation(s) that effect the View's transient state and return <code>true</code> so that
+         * the View can be recycled. Keep in mind that the View in question is already removed from
+         * the RecyclerView.
+         * <p>
+         * In some cases, it is acceptable to recycle a View although it has transient state. Most
+         * of the time, this is a case where the transient state will be cleared in
+         * {@link #onBindViewHolder(ViewHolder, int)} call when View is rebound to a new position.
+         * For this reason, RecyclerView leaves the decision to the Adapter and uses the return
+         * value of this method to decide whether the View should be recycled or not.
+         * <p>
+         * Note that when all animations are created by {@link RecyclerView.ItemAnimator}, you
+         * should never receive this callback because RecyclerView keeps those Views as children
+         * until their animations are complete. This callback is useful when children of the item
+         * views create animations which may not be easy to implement using an {@link ItemAnimator}.
+         * <p>
+         * You should <em>never</em> fix this issue by calling
+         * <code>holder.itemView.setHasTransientState(false);</code> unless you've previously called
+         * <code>holder.itemView.setHasTransientState(true);</code>. Each
+         * <code>View.setHasTransientState(true)</code> call must be matched by a
+         * <code>View.setHasTransientState(false)</code> call, otherwise, the state of the View
+         * may become inconsistent. You should always prefer to end or cancel animations that are
+         * triggering the transient state instead of handling it manually.
+         *
+         * @param holder The ViewHolder containing the View that could not be recycled due to its
+         *               transient state.
+         * @return True if the View should be recycled, false otherwise. Note that if this method
+         * returns <code>true</code>, RecyclerView <em>will ignore</em> the transient state of
+         * the View and recycle it regardless. If this method returns <code>false</code>,
+         * RecyclerView will check the View's transient state again before giving a final decision.
+         * Default implementation returns false.
+         */
+        public boolean onFailedToRecycleView(VH holder) {
+            return false;
+        }
+
+        /**
+         * Called when a view created by this adapter has been attached to a window.
+         *
+         * <p>This can be used as a reasonable signal that the view is about to be seen
+         * by the user. If the adapter previously freed any resources in
+         * {@link #onViewDetachedFromWindow(RecyclerView.ViewHolder) onViewDetachedFromWindow}
+         * those resources should be restored here.</p>
+         *
+         * @param holder Holder of the view being attached
+         */
+        public void onViewAttachedToWindow(VH holder) {
+        }
+
+        /**
+         * Called when a view created by this adapter has been detached from its window.
+         *
+         * <p>Becoming detached from the window is not necessarily a permanent condition;
+         * the consumer of an Adapter's views may choose to cache views offscreen while they
+         * are not visible, attaching and detaching them as appropriate.</p>
+         *
+         * @param holder Holder of the view being detached
+         */
+        public void onViewDetachedFromWindow(VH holder) {
+        }
+
+        /**
+         * Returns true if one or more observers are attached to this adapter.
+         *
+         * @return true if this adapter has observers
+         */
+        public final boolean hasObservers() {
+            return mObservable.hasObservers();
+        }
+
+        /**
+         * Register a new observer to listen for data changes.
+         *
+         * <p>The adapter may publish a variety of events describing specific changes.
+         * Not all adapters may support all change types and some may fall back to a generic
+         * {@link com.android.internal.widget.RecyclerView.AdapterDataObserver#onChanged()
+         * "something changed"} event if more specific data is not available.</p>
+         *
+         * <p>Components registering observers with an adapter are responsible for
+         * {@link #unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver)
+         * unregistering} those observers when finished.</p>
+         *
+         * @param observer Observer to register
+         *
+         * @see #unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver)
+         */
+        public void registerAdapterDataObserver(AdapterDataObserver observer) {
+            mObservable.registerObserver(observer);
+        }
+
+        /**
+         * Unregister an observer currently listening for data changes.
+         *
+         * <p>The unregistered observer will no longer receive events about changes
+         * to the adapter.</p>
+         *
+         * @param observer Observer to unregister
+         *
+         * @see #registerAdapterDataObserver(RecyclerView.AdapterDataObserver)
+         */
+        public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
+            mObservable.unregisterObserver(observer);
+        }
+
+        /**
+         * Called by RecyclerView when it starts observing this Adapter.
+         * <p>
+         * Keep in mind that same adapter may be observed by multiple RecyclerViews.
+         *
+         * @param recyclerView The RecyclerView instance which started observing this adapter.
+         * @see #onDetachedFromRecyclerView(RecyclerView)
+         */
+        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+        }
+
+        /**
+         * Called by RecyclerView when it stops observing this Adapter.
+         *
+         * @param recyclerView The RecyclerView instance which stopped observing this adapter.
+         * @see #onAttachedToRecyclerView(RecyclerView)
+         */
+        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
+        }
+
+        /**
+         * Notify any registered observers that the data set has changed.
+         *
+         * <p>There are two different classes of data change events, item changes and structural
+         * changes. Item changes are when a single item has its data updated but no positional
+         * changes have occurred. Structural changes are when items are inserted, removed or moved
+         * within the data set.</p>
+         *
+         * <p>This event does not specify what about the data set has changed, forcing
+         * any observers to assume that all existing items and structure may no longer be valid.
+         * LayoutManagers will be forced to fully rebind and relayout all visible views.</p>
+         *
+         * <p><code>RecyclerView</code> will attempt to synthesize visible structural change events
+         * for adapters that report that they have {@link #hasStableIds() stable IDs} when
+         * this method is used. This can help for the purposes of animation and visual
+         * object persistence but individual item views will still need to be rebound
+         * and relaid out.</p>
+         *
+         * <p>If you are writing an adapter it will always be more efficient to use the more
+         * specific change events if you can. Rely on <code>notifyDataSetChanged()</code>
+         * as a last resort.</p>
+         *
+         * @see #notifyItemChanged(int)
+         * @see #notifyItemInserted(int)
+         * @see #notifyItemRemoved(int)
+         * @see #notifyItemRangeChanged(int, int)
+         * @see #notifyItemRangeInserted(int, int)
+         * @see #notifyItemRangeRemoved(int, int)
+         */
+        public final void notifyDataSetChanged() {
+            mObservable.notifyChanged();
+        }
+
+        /**
+         * Notify any registered observers that the item at <code>position</code> has changed.
+         * Equivalent to calling <code>notifyItemChanged(position, null);</code>.
+         *
+         * <p>This is an item change event, not a structural change event. It indicates that any
+         * reflection of the data at <code>position</code> is out of date and should be updated.
+         * The item at <code>position</code> retains the same identity.</p>
+         *
+         * @param position Position of the item that has changed
+         *
+         * @see #notifyItemRangeChanged(int, int)
+         */
+        public final void notifyItemChanged(int position) {
+            mObservable.notifyItemRangeChanged(position, 1);
+        }
+
+        /**
+         * Notify any registered observers that the item at <code>position</code> has changed with
+         * an optional payload object.
+         *
+         * <p>This is an item change event, not a structural change event. It indicates that any
+         * reflection of the data at <code>position</code> is out of date and should be updated.
+         * The item at <code>position</code> retains the same identity.
+         * </p>
+         *
+         * <p>
+         * Client can optionally pass a payload for partial change. These payloads will be merged
+         * and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the
+         * item is already represented by a ViewHolder and it will be rebound to the same
+         * ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing
+         * payloads on that item and prevent future payload until
+         * {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume
+         * that the payload will always be passed to onBindViewHolder(), e.g. when the view is not
+         * attached, the payload will be simply dropped.
+         *
+         * @param position Position of the item that has changed
+         * @param payload Optional parameter, use null to identify a "full" update
+         *
+         * @see #notifyItemRangeChanged(int, int)
+         */
+        public final void notifyItemChanged(int position, Object payload) {
+            mObservable.notifyItemRangeChanged(position, 1, payload);
+        }
+
+        /**
+         * Notify any registered observers that the <code>itemCount</code> items starting at
+         * position <code>positionStart</code> have changed.
+         * Equivalent to calling <code>notifyItemRangeChanged(position, itemCount, null);</code>.
+         *
+         * <p>This is an item change event, not a structural change event. It indicates that
+         * any reflection of the data in the given position range is out of date and should
+         * be updated. The items in the given range retain the same identity.</p>
+         *
+         * @param positionStart Position of the first item that has changed
+         * @param itemCount Number of items that have changed
+         *
+         * @see #notifyItemChanged(int)
+         */
+        public final void notifyItemRangeChanged(int positionStart, int itemCount) {
+            mObservable.notifyItemRangeChanged(positionStart, itemCount);
+        }
+
+        /**
+         * Notify any registered observers that the <code>itemCount</code> items starting at
+         * position <code>positionStart</code> have changed. An optional payload can be
+         * passed to each changed item.
+         *
+         * <p>This is an item change event, not a structural change event. It indicates that any
+         * reflection of the data in the given position range is out of date and should be updated.
+         * The items in the given range retain the same identity.
+         * </p>
+         *
+         * <p>
+         * Client can optionally pass a payload for partial change. These payloads will be merged
+         * and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the
+         * item is already represented by a ViewHolder and it will be rebound to the same
+         * ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing
+         * payloads on that item and prevent future payload until
+         * {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume
+         * that the payload will always be passed to onBindViewHolder(), e.g. when the view is not
+         * attached, the payload will be simply dropped.
+         *
+         * @param positionStart Position of the first item that has changed
+         * @param itemCount Number of items that have changed
+         * @param payload  Optional parameter, use null to identify a "full" update
+         *
+         * @see #notifyItemChanged(int)
+         */
+        public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
+            mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);
+        }
+
+        /**
+         * Notify any registered observers that the item reflected at <code>position</code>
+         * has been newly inserted. The item previously at <code>position</code> is now at
+         * position <code>position + 1</code>.
+         *
+         * <p>This is a structural change event. Representations of other existing items in the
+         * data set are still considered up to date and will not be rebound, though their
+         * positions may be altered.</p>
+         *
+         * @param position Position of the newly inserted item in the data set
+         *
+         * @see #notifyItemRangeInserted(int, int)
+         */
+        public final void notifyItemInserted(int position) {
+            mObservable.notifyItemRangeInserted(position, 1);
+        }
+
+        /**
+         * Notify any registered observers that the item reflected at <code>fromPosition</code>
+         * has been moved to <code>toPosition</code>.
+         *
+         * <p>This is a structural change event. Representations of other existing items in the
+         * data set are still considered up to date and will not be rebound, though their
+         * positions may be altered.</p>
+         *
+         * @param fromPosition Previous position of the item.
+         * @param toPosition New position of the item.
+         */
+        public final void notifyItemMoved(int fromPosition, int toPosition) {
+            mObservable.notifyItemMoved(fromPosition, toPosition);
+        }
+
+        /**
+         * Notify any registered observers that the currently reflected <code>itemCount</code>
+         * items starting at <code>positionStart</code> have been newly inserted. The items
+         * previously located at <code>positionStart</code> and beyond can now be found starting
+         * at position <code>positionStart + itemCount</code>.
+         *
+         * <p>This is a structural change event. Representations of other existing items in the
+         * data set are still considered up to date and will not be rebound, though their positions
+         * may be altered.</p>
+         *
+         * @param positionStart Position of the first item that was inserted
+         * @param itemCount Number of items inserted
+         *
+         * @see #notifyItemInserted(int)
+         */
+        public final void notifyItemRangeInserted(int positionStart, int itemCount) {
+            mObservable.notifyItemRangeInserted(positionStart, itemCount);
+        }
+
+        /**
+         * Notify any registered observers that the item previously located at <code>position</code>
+         * has been removed from the data set. The items previously located at and after
+         * <code>position</code> may now be found at <code>oldPosition - 1</code>.
+         *
+         * <p>This is a structural change event. Representations of other existing items in the
+         * data set are still considered up to date and will not be rebound, though their positions
+         * may be altered.</p>
+         *
+         * @param position Position of the item that has now been removed
+         *
+         * @see #notifyItemRangeRemoved(int, int)
+         */
+        public final void notifyItemRemoved(int position) {
+            mObservable.notifyItemRangeRemoved(position, 1);
+        }
+
+        /**
+         * Notify any registered observers that the <code>itemCount</code> items previously
+         * located at <code>positionStart</code> have been removed from the data set. The items
+         * previously located at and after <code>positionStart + itemCount</code> may now be found
+         * at <code>oldPosition - itemCount</code>.
+         *
+         * <p>This is a structural change event. Representations of other existing items in the data
+         * set are still considered up to date and will not be rebound, though their positions
+         * may be altered.</p>
+         *
+         * @param positionStart Previous position of the first item that was removed
+         * @param itemCount Number of items removed from the data set
+         */
+        public final void notifyItemRangeRemoved(int positionStart, int itemCount) {
+            mObservable.notifyItemRangeRemoved(positionStart, itemCount);
+        }
+    }
+
+    void dispatchChildDetached(View child) {
+        final ViewHolder viewHolder = getChildViewHolderInt(child);
+        onChildDetachedFromWindow(child);
+        if (mAdapter != null && viewHolder != null) {
+            mAdapter.onViewDetachedFromWindow(viewHolder);
+        }
+        if (mOnChildAttachStateListeners != null) {
+            final int cnt = mOnChildAttachStateListeners.size();
+            for (int i = cnt - 1; i >= 0; i--) {
+                mOnChildAttachStateListeners.get(i).onChildViewDetachedFromWindow(child);
+            }
+        }
+    }
+
+    void dispatchChildAttached(View child) {
+        final ViewHolder viewHolder = getChildViewHolderInt(child);
+        onChildAttachedToWindow(child);
+        if (mAdapter != null && viewHolder != null) {
+            mAdapter.onViewAttachedToWindow(viewHolder);
+        }
+        if (mOnChildAttachStateListeners != null) {
+            final int cnt = mOnChildAttachStateListeners.size();
+            for (int i = cnt - 1; i >= 0; i--) {
+                mOnChildAttachStateListeners.get(i).onChildViewAttachedToWindow(child);
+            }
+        }
+    }
+
+    /**
+     * A <code>LayoutManager</code> is responsible for measuring and positioning item views
+     * within a <code>RecyclerView</code> as well as determining the policy for when to recycle
+     * item views that are no longer visible to the user. By changing the <code>LayoutManager</code>
+     * a <code>RecyclerView</code> can be used to implement a standard vertically scrolling list,
+     * a uniform grid, staggered grids, horizontally scrolling collections and more. Several stock
+     * layout managers are provided for general use.
+     * <p/>
+     * If the LayoutManager specifies a default constructor or one with the signature
+     * ({@link Context}, {@link AttributeSet}, {@code int}, {@code int}), RecyclerView will
+     * instantiate and set the LayoutManager when being inflated. Most used properties can
+     * be then obtained from {@link #getProperties(Context, AttributeSet, int, int)}. In case
+     * a LayoutManager specifies both constructors, the non-default constructor will take
+     * precedence.
+     *
+     */
+    public abstract static class LayoutManager {
+        ChildHelper mChildHelper;
+        RecyclerView mRecyclerView;
+
+        @Nullable
+        SmoothScroller mSmoothScroller;
+
+        boolean mRequestedSimpleAnimations = false;
+
+        boolean mIsAttachedToWindow = false;
+
+        boolean mAutoMeasure = false;
+
+        /**
+         * LayoutManager has its own more strict measurement cache to avoid re-measuring a child
+         * if the space that will be given to it is already larger than what it has measured before.
+         */
+        private boolean mMeasurementCacheEnabled = true;
+
+        private boolean mItemPrefetchEnabled = true;
+
+        /**
+         * Written by {@link GapWorker} when prefetches occur to track largest number of view ever
+         * requested by a {@link #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)} or
+         * {@link #collectAdjacentPrefetchPositions(int, int, State, LayoutPrefetchRegistry)} call.
+         *
+         * If expanded by a {@link #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)},
+         * will be reset upon layout to prevent initial prefetches (often large, since they're
+         * proportional to expected child count) from expanding cache permanently.
+         */
+        int mPrefetchMaxCountObserved;
+
+        /**
+         * If true, mPrefetchMaxCountObserved is only valid until next layout, and should be reset.
+         */
+        boolean mPrefetchMaxObservedInInitialPrefetch;
+
+        /**
+         * These measure specs might be the measure specs that were passed into RecyclerView's
+         * onMeasure method OR fake measure specs created by the RecyclerView.
+         * For example, when a layout is run, RecyclerView always sets these specs to be
+         * EXACTLY because a LayoutManager cannot resize RecyclerView during a layout pass.
+         * <p>
+         * Also, to be able to use the hint in unspecified measure specs, RecyclerView checks the
+         * API level and sets the size to 0 pre-M to avoid any issue that might be caused by
+         * corrupt values. Older platforms have no responsibility to provide a size if they set
+         * mode to unspecified.
+         */
+        private int mWidthMode, mHeightMode;
+        private int mWidth, mHeight;
+
+
+        /**
+         * Interface for LayoutManagers to request items to be prefetched, based on position, with
+         * specified distance from viewport, which indicates priority.
+         *
+         * @see LayoutManager#collectAdjacentPrefetchPositions(int, int, State, LayoutPrefetchRegistry)
+         * @see LayoutManager#collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)
+         */
+        public interface LayoutPrefetchRegistry {
+            /**
+             * Requests an an item to be prefetched, based on position, with a specified distance,
+             * indicating priority.
+             *
+             * @param layoutPosition Position of the item to prefetch.
+             * @param pixelDistance Distance from the current viewport to the bounds of the item,
+             *                      must be non-negative.
+             */
+            void addPosition(int layoutPosition, int pixelDistance);
+        }
+
+        void setRecyclerView(RecyclerView recyclerView) {
+            if (recyclerView == null) {
+                mRecyclerView = null;
+                mChildHelper = null;
+                mWidth = 0;
+                mHeight = 0;
+            } else {
+                mRecyclerView = recyclerView;
+                mChildHelper = recyclerView.mChildHelper;
+                mWidth = recyclerView.getWidth();
+                mHeight = recyclerView.getHeight();
+            }
+            mWidthMode = MeasureSpec.EXACTLY;
+            mHeightMode = MeasureSpec.EXACTLY;
+        }
+
+        void setMeasureSpecs(int wSpec, int hSpec) {
+            mWidth = MeasureSpec.getSize(wSpec);
+            mWidthMode = MeasureSpec.getMode(wSpec);
+            if (mWidthMode == MeasureSpec.UNSPECIFIED && !ALLOW_SIZE_IN_UNSPECIFIED_SPEC) {
+                mWidth = 0;
+            }
+
+            mHeight = MeasureSpec.getSize(hSpec);
+            mHeightMode = MeasureSpec.getMode(hSpec);
+            if (mHeightMode == MeasureSpec.UNSPECIFIED && !ALLOW_SIZE_IN_UNSPECIFIED_SPEC) {
+                mHeight = 0;
+            }
+        }
+
+        /**
+         * Called after a layout is calculated during a measure pass when using auto-measure.
+         * <p>
+         * It simply traverses all children to calculate a bounding box then calls
+         * {@link #setMeasuredDimension(Rect, int, int)}. LayoutManagers can override that method
+         * if they need to handle the bounding box differently.
+         * <p>
+         * For example, GridLayoutManager override that method to ensure that even if a column is
+         * empty, the GridLayoutManager still measures wide enough to include it.
+         *
+         * @param widthSpec The widthSpec that was passing into RecyclerView's onMeasure
+         * @param heightSpec The heightSpec that was passing into RecyclerView's onMeasure
+         */
+        void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
+            final int count = getChildCount();
+            if (count == 0) {
+                mRecyclerView.defaultOnMeasure(widthSpec, heightSpec);
+                return;
+            }
+            int minX = Integer.MAX_VALUE;
+            int minY = Integer.MAX_VALUE;
+            int maxX = Integer.MIN_VALUE;
+            int maxY = Integer.MIN_VALUE;
+
+            for (int i = 0; i < count; i++) {
+                View child = getChildAt(i);
+                final Rect bounds = mRecyclerView.mTempRect;
+                getDecoratedBoundsWithMargins(child, bounds);
+                if (bounds.left < minX) {
+                    minX = bounds.left;
+                }
+                if (bounds.right > maxX) {
+                    maxX = bounds.right;
+                }
+                if (bounds.top < minY) {
+                    minY = bounds.top;
+                }
+                if (bounds.bottom > maxY) {
+                    maxY = bounds.bottom;
+                }
+            }
+            mRecyclerView.mTempRect.set(minX, minY, maxX, maxY);
+            setMeasuredDimension(mRecyclerView.mTempRect, widthSpec, heightSpec);
+        }
+
+        /**
+         * Sets the measured dimensions from the given bounding box of the children and the
+         * measurement specs that were passed into {@link RecyclerView#onMeasure(int, int)}. It is
+         * called after the RecyclerView calls
+         * {@link LayoutManager#onLayoutChildren(Recycler, State)} during a measurement pass.
+         * <p>
+         * This method should call {@link #setMeasuredDimension(int, int)}.
+         * <p>
+         * The default implementation adds the RecyclerView's padding to the given bounding box
+         * then caps the value to be within the given measurement specs.
+         * <p>
+         * This method is only called if the LayoutManager opted into the auto measurement API.
+         *
+         * @param childrenBounds The bounding box of all children
+         * @param wSpec The widthMeasureSpec that was passed into the RecyclerView.
+         * @param hSpec The heightMeasureSpec that was passed into the RecyclerView.
+         *
+         * @see #setAutoMeasureEnabled(boolean)
+         */
+        public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
+            int usedWidth = childrenBounds.width() + getPaddingLeft() + getPaddingRight();
+            int usedHeight = childrenBounds.height() + getPaddingTop() + getPaddingBottom();
+            int width = chooseSize(wSpec, usedWidth, getMinimumWidth());
+            int height = chooseSize(hSpec, usedHeight, getMinimumHeight());
+            setMeasuredDimension(width, height);
+        }
+
+        /**
+         * Calls {@code RecyclerView#requestLayout} on the underlying RecyclerView
+         */
+        public void requestLayout() {
+            if (mRecyclerView != null) {
+                mRecyclerView.requestLayout();
+            }
+        }
+
+        /**
+         * Checks if RecyclerView is in the middle of a layout or scroll and throws an
+         * {@link IllegalStateException} if it <b>is not</b>.
+         *
+         * @param message The message for the exception. Can be null.
+         * @see #assertNotInLayoutOrScroll(String)
+         */
+        public void assertInLayoutOrScroll(String message) {
+            if (mRecyclerView != null) {
+                mRecyclerView.assertInLayoutOrScroll(message);
+            }
+        }
+
+        /**
+         * Chooses a size from the given specs and parameters that is closest to the desired size
+         * and also complies with the spec.
+         *
+         * @param spec The measureSpec
+         * @param desired The preferred measurement
+         * @param min The minimum value
+         *
+         * @return A size that fits to the given specs
+         */
+        public static int chooseSize(int spec, int desired, int min) {
+            final int mode = View.MeasureSpec.getMode(spec);
+            final int size = View.MeasureSpec.getSize(spec);
+            switch (mode) {
+                case View.MeasureSpec.EXACTLY:
+                    return size;
+                case View.MeasureSpec.AT_MOST:
+                    return Math.min(size, Math.max(desired, min));
+                case View.MeasureSpec.UNSPECIFIED:
+                default:
+                    return Math.max(desired, min);
+            }
+        }
+
+        /**
+         * Checks if RecyclerView is in the middle of a layout or scroll and throws an
+         * {@link IllegalStateException} if it <b>is</b>.
+         *
+         * @param message The message for the exception. Can be null.
+         * @see #assertInLayoutOrScroll(String)
+         */
+        public void assertNotInLayoutOrScroll(String message) {
+            if (mRecyclerView != null) {
+                mRecyclerView.assertNotInLayoutOrScroll(message);
+            }
+        }
+
+        /**
+         * Defines whether the layout should be measured by the RecyclerView or the LayoutManager
+         * wants to handle the layout measurements itself.
+         * <p>
+         * This method is usually called by the LayoutManager with value {@code true} if it wants
+         * to support WRAP_CONTENT. If you are using a public LayoutManager but want to customize
+         * the measurement logic, you can call this method with {@code false} and override
+         * {@link LayoutManager#onMeasure(int, int)} to implement your custom measurement logic.
+         * <p>
+         * AutoMeasure is a convenience mechanism for LayoutManagers to easily wrap their content or
+         * handle various specs provided by the RecyclerView's parent.
+         * It works by calling {@link LayoutManager#onLayoutChildren(Recycler, State)} during an
+         * {@link RecyclerView#onMeasure(int, int)} call, then calculating desired dimensions based
+         * on children's positions. It does this while supporting all existing animation
+         * capabilities of the RecyclerView.
+         * <p>
+         * AutoMeasure works as follows:
+         * <ol>
+         * <li>LayoutManager should call {@code setAutoMeasureEnabled(true)} to enable it. All of
+         * the framework LayoutManagers use {@code auto-measure}.</li>
+         * <li>When {@link RecyclerView#onMeasure(int, int)} is called, if the provided specs are
+         * exact, RecyclerView will only call LayoutManager's {@code onMeasure} and return without
+         * doing any layout calculation.</li>
+         * <li>If one of the layout specs is not {@code EXACT}, the RecyclerView will start the
+         * layout process in {@code onMeasure} call. It will process all pending Adapter updates and
+         * decide whether to run a predictive layout or not. If it decides to do so, it will first
+         * call {@link #onLayoutChildren(Recycler, State)} with {@link State#isPreLayout()} set to
+         * {@code true}. At this stage, {@link #getWidth()} and {@link #getHeight()} will still
+         * return the width and height of the RecyclerView as of the last layout calculation.
+         * <p>
+         * After handling the predictive case, RecyclerView will call
+         * {@link #onLayoutChildren(Recycler, State)} with {@link State#isMeasuring()} set to
+         * {@code true} and {@link State#isPreLayout()} set to {@code false}. The LayoutManager can
+         * access the measurement specs via {@link #getHeight()}, {@link #getHeightMode()},
+         * {@link #getWidth()} and {@link #getWidthMode()}.</li>
+         * <li>After the layout calculation, RecyclerView sets the measured width & height by
+         * calculating the bounding box for the children (+ RecyclerView's padding). The
+         * LayoutManagers can override {@link #setMeasuredDimension(Rect, int, int)} to choose
+         * different values. For instance, GridLayoutManager overrides this value to handle the case
+         * where if it is vertical and has 3 columns but only 2 items, it should still measure its
+         * width to fit 3 items, not 2.</li>
+         * <li>Any following on measure call to the RecyclerView will run
+         * {@link #onLayoutChildren(Recycler, State)} with {@link State#isMeasuring()} set to
+         * {@code true} and {@link State#isPreLayout()} set to {@code false}. RecyclerView will
+         * take care of which views are actually added / removed / moved / changed for animations so
+         * that the LayoutManager should not worry about them and handle each
+         * {@link #onLayoutChildren(Recycler, State)} call as if it is the last one.
+         * </li>
+         * <li>When measure is complete and RecyclerView's
+         * {@link #onLayout(boolean, int, int, int, int)} method is called, RecyclerView checks
+         * whether it already did layout calculations during the measure pass and if so, it re-uses
+         * that information. It may still decide to call {@link #onLayoutChildren(Recycler, State)}
+         * if the last measure spec was different from the final dimensions or adapter contents
+         * have changed between the measure call and the layout call.</li>
+         * <li>Finally, animations are calculated and run as usual.</li>
+         * </ol>
+         *
+         * @param enabled <code>True</code> if the Layout should be measured by the
+         *                             RecyclerView, <code>false</code> if the LayoutManager wants
+         *                             to measure itself.
+         *
+         * @see #setMeasuredDimension(Rect, int, int)
+         * @see #isAutoMeasureEnabled()
+         */
+        public void setAutoMeasureEnabled(boolean enabled) {
+            mAutoMeasure = enabled;
+        }
+
+        /**
+         * Returns whether the LayoutManager uses the automatic measurement API or not.
+         *
+         * @return <code>True</code> if the LayoutManager is measured by the RecyclerView or
+         * <code>false</code> if it measures itself.
+         *
+         * @see #setAutoMeasureEnabled(boolean)
+         */
+        public boolean isAutoMeasureEnabled() {
+            return mAutoMeasure;
+        }
+
+        /**
+         * Returns whether this LayoutManager supports automatic item animations.
+         * A LayoutManager wishing to support item animations should obey certain
+         * rules as outlined in {@link #onLayoutChildren(Recycler, State)}.
+         * The default return value is <code>false</code>, so subclasses of LayoutManager
+         * will not get predictive item animations by default.
+         *
+         * <p>Whether item animations are enabled in a RecyclerView is determined both
+         * by the return value from this method and the
+         * {@link RecyclerView#setItemAnimator(ItemAnimator) ItemAnimator} set on the
+         * RecyclerView itself. If the RecyclerView has a non-null ItemAnimator but this
+         * method returns false, then simple item animations will be enabled, in which
+         * views that are moving onto or off of the screen are simply faded in/out. If
+         * the RecyclerView has a non-null ItemAnimator and this method returns true,
+         * then there will be two calls to {@link #onLayoutChildren(Recycler, State)} to
+         * setup up the information needed to more intelligently predict where appearing
+         * and disappearing views should be animated from/to.</p>
+         *
+         * @return true if predictive item animations should be enabled, false otherwise
+         */
+        public boolean supportsPredictiveItemAnimations() {
+            return false;
+        }
+
+        /**
+         * Sets whether the LayoutManager should be queried for views outside of
+         * its viewport while the UI thread is idle between frames.
+         *
+         * <p>If enabled, the LayoutManager will be queried for items to inflate/bind in between
+         * view system traversals on devices running API 21 or greater. Default value is true.</p>
+         *
+         * <p>On platforms API level 21 and higher, the UI thread is idle between passing a frame
+         * to RenderThread and the starting up its next frame at the next VSync pulse. By
+         * prefetching out of window views in this time period, delays from inflation and view
+         * binding are much less likely to cause jank and stuttering during scrolls and flings.</p>
+         *
+         * <p>While prefetch is enabled, it will have the side effect of expanding the effective
+         * size of the View cache to hold prefetched views.</p>
+         *
+         * @param enabled <code>True</code> if items should be prefetched in between traversals.
+         *
+         * @see #isItemPrefetchEnabled()
+         */
+        public final void setItemPrefetchEnabled(boolean enabled) {
+            if (enabled != mItemPrefetchEnabled) {
+                mItemPrefetchEnabled = enabled;
+                mPrefetchMaxCountObserved = 0;
+                if (mRecyclerView != null) {
+                    mRecyclerView.mRecycler.updateViewCacheSize();
+                }
+            }
+        }
+
+        /**
+         * Sets whether the LayoutManager should be queried for views outside of
+         * its viewport while the UI thread is idle between frames.
+         *
+         * @see #setItemPrefetchEnabled(boolean)
+         *
+         * @return true if item prefetch is enabled, false otherwise
+         */
+        public final boolean isItemPrefetchEnabled() {
+            return mItemPrefetchEnabled;
+        }
+
+        /**
+         * Gather all positions from the LayoutManager to be prefetched, given specified momentum.
+         *
+         * <p>If item prefetch is enabled, this method is called in between traversals to gather
+         * which positions the LayoutManager will soon need, given upcoming movement in subsequent
+         * traversals.</p>
+         *
+         * <p>The LayoutManager should call {@link LayoutPrefetchRegistry#addPosition(int, int)} for
+         * each item to be prepared, and these positions will have their ViewHolders created and
+         * bound, if there is sufficient time available, in advance of being needed by a
+         * scroll or layout.</p>
+         *
+         * @param dx X movement component.
+         * @param dy Y movement component.
+         * @param state State of RecyclerView
+         * @param layoutPrefetchRegistry PrefetchRegistry to add prefetch entries into.
+         *
+         * @see #isItemPrefetchEnabled()
+         * @see #collectInitialPrefetchPositions(int, LayoutPrefetchRegistry)
+         */
+        public void collectAdjacentPrefetchPositions(int dx, int dy, State state,
+                LayoutPrefetchRegistry layoutPrefetchRegistry) {}
+
+        /**
+         * Gather all positions from the LayoutManager to be prefetched in preperation for its
+         * RecyclerView to come on screen, due to the movement of another, containing RecyclerView.
+         *
+         * <p>This method is only called when a RecyclerView is nested in another RecyclerView.</p>
+         *
+         * <p>If item prefetch is enabled for this LayoutManager, as well in another containing
+         * LayoutManager, this method is called in between draw traversals to gather
+         * which positions this LayoutManager will first need, once it appears on the screen.</p>
+         *
+         * <p>For example, if this LayoutManager represents a horizontally scrolling list within a
+         * vertically scrolling LayoutManager, this method would be called when the horizontal list
+         * is about to come onscreen.</p>
+         *
+         * <p>The LayoutManager should call {@link LayoutPrefetchRegistry#addPosition(int, int)} for
+         * each item to be prepared, and these positions will have their ViewHolders created and
+         * bound, if there is sufficient time available, in advance of being needed by a
+         * scroll or layout.</p>
+         *
+         * @param adapterItemCount number of items in the associated adapter.
+         * @param layoutPrefetchRegistry PrefetchRegistry to add prefetch entries into.
+         *
+         * @see #isItemPrefetchEnabled()
+         * @see #collectAdjacentPrefetchPositions(int, int, State, LayoutPrefetchRegistry)
+         */
+        public void collectInitialPrefetchPositions(int adapterItemCount,
+                LayoutPrefetchRegistry layoutPrefetchRegistry) {}
+
+        void dispatchAttachedToWindow(RecyclerView view) {
+            mIsAttachedToWindow = true;
+            onAttachedToWindow(view);
+        }
+
+        void dispatchDetachedFromWindow(RecyclerView view, Recycler recycler) {
+            mIsAttachedToWindow = false;
+            onDetachedFromWindow(view, recycler);
+        }
+
+        /**
+         * Returns whether LayoutManager is currently attached to a RecyclerView which is attached
+         * to a window.
+         *
+         * @return True if this LayoutManager is controlling a RecyclerView and the RecyclerView
+         * is attached to window.
+         */
+        public boolean isAttachedToWindow() {
+            return mIsAttachedToWindow;
+        }
+
+        /**
+         * Causes the Runnable to execute on the next animation time step.
+         * The runnable will be run on the user interface thread.
+         * <p>
+         * Calling this method when LayoutManager is not attached to a RecyclerView has no effect.
+         *
+         * @param action The Runnable that will be executed.
+         *
+         * @see #removeCallbacks
+         */
+        public void postOnAnimation(Runnable action) {
+            if (mRecyclerView != null) {
+                mRecyclerView.postOnAnimation(action);
+            }
+        }
+
+        /**
+         * Removes the specified Runnable from the message queue.
+         * <p>
+         * Calling this method when LayoutManager is not attached to a RecyclerView has no effect.
+         *
+         * @param action The Runnable to remove from the message handling queue
+         *
+         * @return true if RecyclerView could ask the Handler to remove the Runnable,
+         *         false otherwise. When the returned value is true, the Runnable
+         *         may or may not have been actually removed from the message queue
+         *         (for instance, if the Runnable was not in the queue already.)
+         *
+         * @see #postOnAnimation
+         */
+        public boolean removeCallbacks(Runnable action) {
+            if (mRecyclerView != null) {
+                return mRecyclerView.removeCallbacks(action);
+            }
+            return false;
+        }
+        /**
+         * Called when this LayoutManager is both attached to a RecyclerView and that RecyclerView
+         * is attached to a window.
+         * <p>
+         * If the RecyclerView is re-attached with the same LayoutManager and Adapter, it may not
+         * call {@link #onLayoutChildren(Recycler, State)} if nothing has changed and a layout was
+         * not requested on the RecyclerView while it was detached.
+         * <p>
+         * Subclass implementations should always call through to the superclass implementation.
+         *
+         * @param view The RecyclerView this LayoutManager is bound to
+         *
+         * @see #onDetachedFromWindow(RecyclerView, Recycler)
+         */
+        @CallSuper
+        public void onAttachedToWindow(RecyclerView view) {
+        }
+
+        /**
+         * @deprecated
+         * override {@link #onDetachedFromWindow(RecyclerView, Recycler)}
+         */
+        @Deprecated
+        public void onDetachedFromWindow(RecyclerView view) {
+
+        }
+
+        /**
+         * Called when this LayoutManager is detached from its parent RecyclerView or when
+         * its parent RecyclerView is detached from its window.
+         * <p>
+         * LayoutManager should clear all of its View references as another LayoutManager might be
+         * assigned to the RecyclerView.
+         * <p>
+         * If the RecyclerView is re-attached with the same LayoutManager and Adapter, it may not
+         * call {@link #onLayoutChildren(Recycler, State)} if nothing has changed and a layout was
+         * not requested on the RecyclerView while it was detached.
+         * <p>
+         * If your LayoutManager has View references that it cleans in on-detach, it should also
+         * call {@link RecyclerView#requestLayout()} to ensure that it is re-laid out when
+         * RecyclerView is re-attached.
+         * <p>
+         * Subclass implementations should always call through to the superclass implementation.
+         *
+         * @param view The RecyclerView this LayoutManager is bound to
+         * @param recycler The recycler to use if you prefer to recycle your children instead of
+         *                 keeping them around.
+         *
+         * @see #onAttachedToWindow(RecyclerView)
+         */
+        @CallSuper
+        public void onDetachedFromWindow(RecyclerView view, Recycler recycler) {
+            onDetachedFromWindow(view);
+        }
+
+        /**
+         * Check if the RecyclerView is configured to clip child views to its padding.
+         *
+         * @return true if this RecyclerView clips children to its padding, false otherwise
+         */
+        public boolean getClipToPadding() {
+            return mRecyclerView != null && mRecyclerView.mClipToPadding;
+        }
+
+        /**
+         * Lay out all relevant child views from the given adapter.
+         *
+         * The LayoutManager is in charge of the behavior of item animations. By default,
+         * RecyclerView has a non-null {@link #getItemAnimator() ItemAnimator}, and simple
+         * item animations are enabled. This means that add/remove operations on the
+         * adapter will result in animations to add new or appearing items, removed or
+         * disappearing items, and moved items. If a LayoutManager returns false from
+         * {@link #supportsPredictiveItemAnimations()}, which is the default, and runs a
+         * normal layout operation during {@link #onLayoutChildren(Recycler, State)}, the
+         * RecyclerView will have enough information to run those animations in a simple
+         * way. For example, the default ItemAnimator, {@link DefaultItemAnimator}, will
+         * simply fade views in and out, whether they are actually added/removed or whether
+         * they are moved on or off the screen due to other add/remove operations.
+         *
+         * <p>A LayoutManager wanting a better item animation experience, where items can be
+         * animated onto and off of the screen according to where the items exist when they
+         * are not on screen, then the LayoutManager should return true from
+         * {@link #supportsPredictiveItemAnimations()} and add additional logic to
+         * {@link #onLayoutChildren(Recycler, State)}. Supporting predictive animations
+         * means that {@link #onLayoutChildren(Recycler, State)} will be called twice;
+         * once as a "pre" layout step to determine where items would have been prior to
+         * a real layout, and again to do the "real" layout. In the pre-layout phase,
+         * items will remember their pre-layout positions to allow them to be laid out
+         * appropriately. Also, {@link LayoutParams#isItemRemoved() removed} items will
+         * be returned from the scrap to help determine correct placement of other items.
+         * These removed items should not be added to the child list, but should be used
+         * to help calculate correct positioning of other views, including views that
+         * were not previously onscreen (referred to as APPEARING views), but whose
+         * pre-layout offscreen position can be determined given the extra
+         * information about the pre-layout removed views.</p>
+         *
+         * <p>The second layout pass is the real layout in which only non-removed views
+         * will be used. The only additional requirement during this pass is, if
+         * {@link #supportsPredictiveItemAnimations()} returns true, to note which
+         * views exist in the child list prior to layout and which are not there after
+         * layout (referred to as DISAPPEARING views), and to position/layout those views
+         * appropriately, without regard to the actual bounds of the RecyclerView. This allows
+         * the animation system to know the location to which to animate these disappearing
+         * views.</p>
+         *
+         * <p>The default LayoutManager implementations for RecyclerView handle all of these
+         * requirements for animations already. Clients of RecyclerView can either use one
+         * of these layout managers directly or look at their implementations of
+         * onLayoutChildren() to see how they account for the APPEARING and
+         * DISAPPEARING views.</p>
+         *
+         * @param recycler         Recycler to use for fetching potentially cached views for a
+         *                         position
+         * @param state            Transient state of RecyclerView
+         */
+        public void onLayoutChildren(Recycler recycler, State state) {
+            Log.e(TAG, "You must override onLayoutChildren(Recycler recycler, State state) ");
+        }
+
+        /**
+         * Called after a full layout calculation is finished. The layout calculation may include
+         * multiple {@link #onLayoutChildren(Recycler, State)} calls due to animations or
+         * layout measurement but it will include only one {@link #onLayoutCompleted(State)} call.
+         * This method will be called at the end of {@link View#layout(int, int, int, int)} call.
+         * <p>
+         * This is a good place for the LayoutManager to do some cleanup like pending scroll
+         * position, saved state etc.
+         *
+         * @param state Transient state of RecyclerView
+         */
+        public void onLayoutCompleted(State state) {
+        }
+
+        /**
+         * Create a default <code>LayoutParams</code> object for a child of the RecyclerView.
+         *
+         * <p>LayoutManagers will often want to use a custom <code>LayoutParams</code> type
+         * to store extra information specific to the layout. Client code should subclass
+         * {@link RecyclerView.LayoutParams} for this purpose.</p>
+         *
+         * <p><em>Important:</em> if you use your own custom <code>LayoutParams</code> type
+         * you must also override
+         * {@link #checkLayoutParams(LayoutParams)},
+         * {@link #generateLayoutParams(android.view.ViewGroup.LayoutParams)} and
+         * {@link #generateLayoutParams(android.content.Context, android.util.AttributeSet)}.</p>
+         *
+         * @return A new LayoutParams for a child view
+         */
+        public abstract LayoutParams generateDefaultLayoutParams();
+
+        /**
+         * Determines the validity of the supplied LayoutParams object.
+         *
+         * <p>This should check to make sure that the object is of the correct type
+         * and all values are within acceptable ranges. The default implementation
+         * returns <code>true</code> for non-null params.</p>
+         *
+         * @param lp LayoutParams object to check
+         * @return true if this LayoutParams object is valid, false otherwise
+         */
+        public boolean checkLayoutParams(LayoutParams lp) {
+            return lp != null;
+        }
+
+        /**
+         * Create a LayoutParams object suitable for this LayoutManager, copying relevant
+         * values from the supplied LayoutParams object if possible.
+         *
+         * <p><em>Important:</em> if you use your own custom <code>LayoutParams</code> type
+         * you must also override
+         * {@link #checkLayoutParams(LayoutParams)},
+         * {@link #generateLayoutParams(android.view.ViewGroup.LayoutParams)} and
+         * {@link #generateLayoutParams(android.content.Context, android.util.AttributeSet)}.</p>
+         *
+         * @param lp Source LayoutParams object to copy values from
+         * @return a new LayoutParams object
+         */
+        public LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+            if (lp instanceof LayoutParams) {
+                return new LayoutParams((LayoutParams) lp);
+            } else if (lp instanceof MarginLayoutParams) {
+                return new LayoutParams((MarginLayoutParams) lp);
+            } else {
+                return new LayoutParams(lp);
+            }
+        }
+
+        /**
+         * Create a LayoutParams object suitable for this LayoutManager from
+         * an inflated layout resource.
+         *
+         * <p><em>Important:</em> if you use your own custom <code>LayoutParams</code> type
+         * you must also override
+         * {@link #checkLayoutParams(LayoutParams)},
+         * {@link #generateLayoutParams(android.view.ViewGroup.LayoutParams)} and
+         * {@link #generateLayoutParams(android.content.Context, android.util.AttributeSet)}.</p>
+         *
+         * @param c Context for obtaining styled attributes
+         * @param attrs AttributeSet describing the supplied arguments
+         * @return a new LayoutParams object
+         */
+        public LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
+            return new LayoutParams(c, attrs);
+        }
+
+        /**
+         * Scroll horizontally by dx pixels in screen coordinates and return the distance traveled.
+         * The default implementation does nothing and returns 0.
+         *
+         * @param dx            distance to scroll by in pixels. X increases as scroll position
+         *                      approaches the right.
+         * @param recycler      Recycler to use for fetching potentially cached views for a
+         *                      position
+         * @param state         Transient state of RecyclerView
+         * @return The actual distance scrolled. The return value will be negative if dx was
+         * negative and scrolling proceeeded in that direction.
+         * <code>Math.abs(result)</code> may be less than dx if a boundary was reached.
+         */
+        public int scrollHorizontallyBy(int dx, Recycler recycler, State state) {
+            return 0;
+        }
+
+        /**
+         * Scroll vertically by dy pixels in screen coordinates and return the distance traveled.
+         * The default implementation does nothing and returns 0.
+         *
+         * @param dy            distance to scroll in pixels. Y increases as scroll position
+         *                      approaches the bottom.
+         * @param recycler      Recycler to use for fetching potentially cached views for a
+         *                      position
+         * @param state         Transient state of RecyclerView
+         * @return The actual distance scrolled. The return value will be negative if dy was
+         * negative and scrolling proceeeded in that direction.
+         * <code>Math.abs(result)</code> may be less than dy if a boundary was reached.
+         */
+        public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
+            return 0;
+        }
+
+        /**
+         * Query if horizontal scrolling is currently supported. The default implementation
+         * returns false.
+         *
+         * @return True if this LayoutManager can scroll the current contents horizontally
+         */
+        public boolean canScrollHorizontally() {
+            return false;
+        }
+
+        /**
+         * Query if vertical scrolling is currently supported. The default implementation
+         * returns false.
+         *
+         * @return True if this LayoutManager can scroll the current contents vertically
+         */
+        public boolean canScrollVertically() {
+            return false;
+        }
+
+        /**
+         * Scroll to the specified adapter position.
+         *
+         * Actual position of the item on the screen depends on the LayoutManager implementation.
+         * @param position Scroll to this adapter position.
+         */
+        public void scrollToPosition(int position) {
+            if (DEBUG) {
+                Log.e(TAG, "You MUST implement scrollToPosition. It will soon become abstract");
+            }
+        }
+
+        /**
+         * <p>Smooth scroll to the specified adapter position.</p>
+         * <p>To support smooth scrolling, override this method, create your {@link SmoothScroller}
+         * instance and call {@link #startSmoothScroll(SmoothScroller)}.
+         * </p>
+         * @param recyclerView The RecyclerView to which this layout manager is attached
+         * @param state    Current State of RecyclerView
+         * @param position Scroll to this adapter position.
+         */
+        public void smoothScrollToPosition(RecyclerView recyclerView, State state,
+                int position) {
+            Log.e(TAG, "You must override smoothScrollToPosition to support smooth scrolling");
+        }
+
+        /**
+         * <p>Starts a smooth scroll using the provided SmoothScroller.</p>
+         * <p>Calling this method will cancel any previous smooth scroll request.</p>
+         * @param smoothScroller Instance which defines how smooth scroll should be animated
+         */
+        public void startSmoothScroll(SmoothScroller smoothScroller) {
+            if (mSmoothScroller != null && smoothScroller != mSmoothScroller
+                    && mSmoothScroller.isRunning()) {
+                mSmoothScroller.stop();
+            }
+            mSmoothScroller = smoothScroller;
+            mSmoothScroller.start(mRecyclerView, this);
+        }
+
+        /**
+         * @return true if RecycylerView is currently in the state of smooth scrolling.
+         */
+        public boolean isSmoothScrolling() {
+            return mSmoothScroller != null && mSmoothScroller.isRunning();
+        }
+
+
+        /**
+         * Returns the resolved layout direction for this RecyclerView.
+         *
+         * @return {@link android.view.View#LAYOUT_DIRECTION_RTL} if the layout
+         * direction is RTL or returns
+         * {@link android.view.View#LAYOUT_DIRECTION_LTR} if the layout direction
+         * is not RTL.
+         */
+        public int getLayoutDirection() {
+            return mRecyclerView.getLayoutDirection();
+        }
+
+        /**
+         * Ends all animations on the view created by the {@link ItemAnimator}.
+         *
+         * @param view The View for which the animations should be ended.
+         * @see RecyclerView.ItemAnimator#endAnimations()
+         */
+        public void endAnimation(View view) {
+            if (mRecyclerView.mItemAnimator != null) {
+                mRecyclerView.mItemAnimator.endAnimation(getChildViewHolderInt(view));
+            }
+        }
+
+        /**
+         * To be called only during {@link #onLayoutChildren(Recycler, State)} to add a view
+         * to the layout that is known to be going away, either because it has been
+         * {@link Adapter#notifyItemRemoved(int) removed} or because it is actually not in the
+         * visible portion of the container but is being laid out in order to inform RecyclerView
+         * in how to animate the item out of view.
+         * <p>
+         * Views added via this method are going to be invisible to LayoutManager after the
+         * dispatchLayout pass is complete. They cannot be retrieved via {@link #getChildAt(int)}
+         * or won't be included in {@link #getChildCount()} method.
+         *
+         * @param child View to add and then remove with animation.
+         */
+        public void addDisappearingView(View child) {
+            addDisappearingView(child, -1);
+        }
+
+        /**
+         * To be called only during {@link #onLayoutChildren(Recycler, State)} to add a view
+         * to the layout that is known to be going away, either because it has been
+         * {@link Adapter#notifyItemRemoved(int) removed} or because it is actually not in the
+         * visible portion of the container but is being laid out in order to inform RecyclerView
+         * in how to animate the item out of view.
+         * <p>
+         * Views added via this method are going to be invisible to LayoutManager after the
+         * dispatchLayout pass is complete. They cannot be retrieved via {@link #getChildAt(int)}
+         * or won't be included in {@link #getChildCount()} method.
+         *
+         * @param child View to add and then remove with animation.
+         * @param index Index of the view.
+         */
+        public void addDisappearingView(View child, int index) {
+            addViewInt(child, index, true);
+        }
+
+        /**
+         * Add a view to the currently attached RecyclerView if needed. LayoutManagers should
+         * use this method to add views obtained from a {@link Recycler} using
+         * {@link Recycler#getViewForPosition(int)}.
+         *
+         * @param child View to add
+         */
+        public void addView(View child) {
+            addView(child, -1);
+        }
+
+        /**
+         * Add a view to the currently attached RecyclerView if needed. LayoutManagers should
+         * use this method to add views obtained from a {@link Recycler} using
+         * {@link Recycler#getViewForPosition(int)}.
+         *
+         * @param child View to add
+         * @param index Index to add child at
+         */
+        public void addView(View child, int index) {
+            addViewInt(child, index, false);
+        }
+
+        private void addViewInt(View child, int index, boolean disappearing) {
+            final ViewHolder holder = getChildViewHolderInt(child);
+            if (disappearing || holder.isRemoved()) {
+                // these views will be hidden at the end of the layout pass.
+                mRecyclerView.mViewInfoStore.addToDisappearedInLayout(holder);
+            } else {
+                // This may look like unnecessary but may happen if layout manager supports
+                // predictive layouts and adapter removed then re-added the same item.
+                // In this case, added version will be visible in the post layout (because add is
+                // deferred) but RV will still bind it to the same View.
+                // So if a View re-appears in post layout pass, remove it from disappearing list.
+                mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(holder);
+            }
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (holder.wasReturnedFromScrap() || holder.isScrap()) {
+                if (holder.isScrap()) {
+                    holder.unScrap();
+                } else {
+                    holder.clearReturnedFromScrapFlag();
+                }
+                mChildHelper.attachViewToParent(child, index, child.getLayoutParams(), false);
+                if (DISPATCH_TEMP_DETACH) {
+                    child.dispatchFinishTemporaryDetach();
+                }
+            } else if (child.getParent() == mRecyclerView) { // it was not a scrap but a valid child
+                // ensure in correct position
+                int currentIndex = mChildHelper.indexOfChild(child);
+                if (index == -1) {
+                    index = mChildHelper.getChildCount();
+                }
+                if (currentIndex == -1) {
+                    throw new IllegalStateException("Added View has RecyclerView as parent but"
+                            + " view is not a real child. Unfiltered index:"
+                            + mRecyclerView.indexOfChild(child));
+                }
+                if (currentIndex != index) {
+                    mRecyclerView.mLayout.moveView(currentIndex, index);
+                }
+            } else {
+                mChildHelper.addView(child, index, false);
+                lp.mInsetsDirty = true;
+                if (mSmoothScroller != null && mSmoothScroller.isRunning()) {
+                    mSmoothScroller.onChildAttachedToWindow(child);
+                }
+            }
+            if (lp.mPendingInvalidate) {
+                if (DEBUG) {
+                    Log.d(TAG, "consuming pending invalidate on child " + lp.mViewHolder);
+                }
+                holder.itemView.invalidate();
+                lp.mPendingInvalidate = false;
+            }
+        }
+
+        /**
+         * Remove a view from the currently attached RecyclerView if needed. LayoutManagers should
+         * use this method to completely remove a child view that is no longer needed.
+         * LayoutManagers should strongly consider recycling removed views using
+         * {@link Recycler#recycleView(android.view.View)}.
+         *
+         * @param child View to remove
+         */
+        public void removeView(View child) {
+            mChildHelper.removeView(child);
+        }
+
+        /**
+         * Remove a view from the currently attached RecyclerView if needed. LayoutManagers should
+         * use this method to completely remove a child view that is no longer needed.
+         * LayoutManagers should strongly consider recycling removed views using
+         * {@link Recycler#recycleView(android.view.View)}.
+         *
+         * @param index Index of the child view to remove
+         */
+        public void removeViewAt(int index) {
+            final View child = getChildAt(index);
+            if (child != null) {
+                mChildHelper.removeViewAt(index);
+            }
+        }
+
+        /**
+         * Remove all views from the currently attached RecyclerView. This will not recycle
+         * any of the affected views; the LayoutManager is responsible for doing so if desired.
+         */
+        public void removeAllViews() {
+            // Only remove non-animating views
+            final int childCount = getChildCount();
+            for (int i = childCount - 1; i >= 0; i--) {
+                mChildHelper.removeViewAt(i);
+            }
+        }
+
+        /**
+         * Returns offset of the RecyclerView's text baseline from the its top boundary.
+         *
+         * @return The offset of the RecyclerView's text baseline from the its top boundary; -1 if
+         * there is no baseline.
+         */
+        public int getBaseline() {
+            return -1;
+        }
+
+        /**
+         * Returns the adapter position of the item represented by the given View. This does not
+         * contain any adapter changes that might have happened after the last layout.
+         *
+         * @param view The view to query
+         * @return The adapter position of the item which is rendered by this View.
+         */
+        public int getPosition(View view) {
+            return ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
+        }
+
+        /**
+         * Returns the View type defined by the adapter.
+         *
+         * @param view The view to query
+         * @return The type of the view assigned by the adapter.
+         */
+        public int getItemViewType(View view) {
+            return getChildViewHolderInt(view).getItemViewType();
+        }
+
+        /**
+         * Traverses the ancestors of the given view and returns the item view that contains it
+         * and also a direct child of the LayoutManager.
+         * <p>
+         * Note that this method may return null if the view is a child of the RecyclerView but
+         * not a child of the LayoutManager (e.g. running a disappear animation).
+         *
+         * @param view The view that is a descendant of the LayoutManager.
+         *
+         * @return The direct child of the LayoutManager which contains the given view or null if
+         * the provided view is not a descendant of this LayoutManager.
+         *
+         * @see RecyclerView#getChildViewHolder(View)
+         * @see RecyclerView#findContainingViewHolder(View)
+         */
+        @Nullable
+        public View findContainingItemView(View view) {
+            if (mRecyclerView == null) {
+                return null;
+            }
+            View found = mRecyclerView.findContainingItemView(view);
+            if (found == null) {
+                return null;
+            }
+            if (mChildHelper.isHidden(found)) {
+                return null;
+            }
+            return found;
+        }
+
+        /**
+         * Finds the view which represents the given adapter position.
+         * <p>
+         * This method traverses each child since it has no information about child order.
+         * Override this method to improve performance if your LayoutManager keeps data about
+         * child views.
+         * <p>
+         * If a view is ignored via {@link #ignoreView(View)}, it is also ignored by this method.
+         *
+         * @param position Position of the item in adapter
+         * @return The child view that represents the given position or null if the position is not
+         * laid out
+         */
+        public View findViewByPosition(int position) {
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                ViewHolder vh = getChildViewHolderInt(child);
+                if (vh == null) {
+                    continue;
+                }
+                if (vh.getLayoutPosition() == position && !vh.shouldIgnore()
+                        && (mRecyclerView.mState.isPreLayout() || !vh.isRemoved())) {
+                    return child;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Temporarily detach a child view.
+         *
+         * <p>LayoutManagers may want to perform a lightweight detach operation to rearrange
+         * views currently attached to the RecyclerView. Generally LayoutManager implementations
+         * will want to use {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)}
+         * so that the detached view may be rebound and reused.</p>
+         *
+         * <p>If a LayoutManager uses this method to detach a view, it <em>must</em>
+         * {@link #attachView(android.view.View, int, RecyclerView.LayoutParams) reattach}
+         * or {@link #removeDetachedView(android.view.View) fully remove} the detached view
+         * before the LayoutManager entry point method called by RecyclerView returns.</p>
+         *
+         * @param child Child to detach
+         */
+        public void detachView(View child) {
+            final int ind = mChildHelper.indexOfChild(child);
+            if (ind >= 0) {
+                detachViewInternal(ind, child);
+            }
+        }
+
+        /**
+         * Temporarily detach a child view.
+         *
+         * <p>LayoutManagers may want to perform a lightweight detach operation to rearrange
+         * views currently attached to the RecyclerView. Generally LayoutManager implementations
+         * will want to use {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)}
+         * so that the detached view may be rebound and reused.</p>
+         *
+         * <p>If a LayoutManager uses this method to detach a view, it <em>must</em>
+         * {@link #attachView(android.view.View, int, RecyclerView.LayoutParams) reattach}
+         * or {@link #removeDetachedView(android.view.View) fully remove} the detached view
+         * before the LayoutManager entry point method called by RecyclerView returns.</p>
+         *
+         * @param index Index of the child to detach
+         */
+        public void detachViewAt(int index) {
+            detachViewInternal(index, getChildAt(index));
+        }
+
+        private void detachViewInternal(int index, View view) {
+            if (DISPATCH_TEMP_DETACH) {
+                view.dispatchStartTemporaryDetach();
+            }
+            mChildHelper.detachViewFromParent(index);
+        }
+
+        /**
+         * Reattach a previously {@link #detachView(android.view.View) detached} view.
+         * This method should not be used to reattach views that were previously
+         * {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)}  scrapped}.
+         *
+         * @param child Child to reattach
+         * @param index Intended child index for child
+         * @param lp LayoutParams for child
+         */
+        public void attachView(View child, int index, LayoutParams lp) {
+            ViewHolder vh = getChildViewHolderInt(child);
+            if (vh.isRemoved()) {
+                mRecyclerView.mViewInfoStore.addToDisappearedInLayout(vh);
+            } else {
+                mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(vh);
+            }
+            mChildHelper.attachViewToParent(child, index, lp, vh.isRemoved());
+            if (DISPATCH_TEMP_DETACH)  {
+                child.dispatchFinishTemporaryDetach();
+            }
+        }
+
+        /**
+         * Reattach a previously {@link #detachView(android.view.View) detached} view.
+         * This method should not be used to reattach views that were previously
+         * {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)}  scrapped}.
+         *
+         * @param child Child to reattach
+         * @param index Intended child index for child
+         */
+        public void attachView(View child, int index) {
+            attachView(child, index, (LayoutParams) child.getLayoutParams());
+        }
+
+        /**
+         * Reattach a previously {@link #detachView(android.view.View) detached} view.
+         * This method should not be used to reattach views that were previously
+         * {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)}  scrapped}.
+         *
+         * @param child Child to reattach
+         */
+        public void attachView(View child) {
+            attachView(child, -1);
+        }
+
+        /**
+         * Finish removing a view that was previously temporarily
+         * {@link #detachView(android.view.View) detached}.
+         *
+         * @param child Detached child to remove
+         */
+        public void removeDetachedView(View child) {
+            mRecyclerView.removeDetachedView(child, false);
+        }
+
+        /**
+         * Moves a View from one position to another.
+         *
+         * @param fromIndex The View's initial index
+         * @param toIndex The View's target index
+         */
+        public void moveView(int fromIndex, int toIndex) {
+            View view = getChildAt(fromIndex);
+            if (view == null) {
+                throw new IllegalArgumentException("Cannot move a child from non-existing index:"
+                        + fromIndex);
+            }
+            detachViewAt(fromIndex);
+            attachView(view, toIndex);
+        }
+
+        /**
+         * Detach a child view and add it to a {@link Recycler Recycler's} scrap heap.
+         *
+         * <p>Scrapping a view allows it to be rebound and reused to show updated or
+         * different data.</p>
+         *
+         * @param child Child to detach and scrap
+         * @param recycler Recycler to deposit the new scrap view into
+         */
+        public void detachAndScrapView(View child, Recycler recycler) {
+            int index = mChildHelper.indexOfChild(child);
+            scrapOrRecycleView(recycler, index, child);
+        }
+
+        /**
+         * Detach a child view and add it to a {@link Recycler Recycler's} scrap heap.
+         *
+         * <p>Scrapping a view allows it to be rebound and reused to show updated or
+         * different data.</p>
+         *
+         * @param index Index of child to detach and scrap
+         * @param recycler Recycler to deposit the new scrap view into
+         */
+        public void detachAndScrapViewAt(int index, Recycler recycler) {
+            final View child = getChildAt(index);
+            scrapOrRecycleView(recycler, index, child);
+        }
+
+        /**
+         * Remove a child view and recycle it using the given Recycler.
+         *
+         * @param child Child to remove and recycle
+         * @param recycler Recycler to use to recycle child
+         */
+        public void removeAndRecycleView(View child, Recycler recycler) {
+            removeView(child);
+            recycler.recycleView(child);
+        }
+
+        /**
+         * Remove a child view and recycle it using the given Recycler.
+         *
+         * @param index Index of child to remove and recycle
+         * @param recycler Recycler to use to recycle child
+         */
+        public void removeAndRecycleViewAt(int index, Recycler recycler) {
+            final View view = getChildAt(index);
+            removeViewAt(index);
+            recycler.recycleView(view);
+        }
+
+        /**
+         * Return the current number of child views attached to the parent RecyclerView.
+         * This does not include child views that were temporarily detached and/or scrapped.
+         *
+         * @return Number of attached children
+         */
+        public int getChildCount() {
+            return mChildHelper != null ? mChildHelper.getChildCount() : 0;
+        }
+
+        /**
+         * Return the child view at the given index
+         * @param index Index of child to return
+         * @return Child view at index
+         */
+        public View getChildAt(int index) {
+            return mChildHelper != null ? mChildHelper.getChildAt(index) : null;
+        }
+
+        /**
+         * Return the width measurement spec mode of the RecyclerView.
+         * <p>
+         * This value is set only if the LayoutManager opts into the auto measure api via
+         * {@link #setAutoMeasureEnabled(boolean)}.
+         * <p>
+         * When RecyclerView is running a layout, this value is always set to
+         * {@link View.MeasureSpec#EXACTLY} even if it was measured with a different spec mode.
+         *
+         * @return Width measure spec mode.
+         *
+         * @see View.MeasureSpec#getMode(int)
+         * @see View#onMeasure(int, int)
+         */
+        public int getWidthMode() {
+            return mWidthMode;
+        }
+
+        /**
+         * Return the height measurement spec mode of the RecyclerView.
+         * <p>
+         * This value is set only if the LayoutManager opts into the auto measure api via
+         * {@link #setAutoMeasureEnabled(boolean)}.
+         * <p>
+         * When RecyclerView is running a layout, this value is always set to
+         * {@link View.MeasureSpec#EXACTLY} even if it was measured with a different spec mode.
+         *
+         * @return Height measure spec mode.
+         *
+         * @see View.MeasureSpec#getMode(int)
+         * @see View#onMeasure(int, int)
+         */
+        public int getHeightMode() {
+            return mHeightMode;
+        }
+
+        /**
+         * Return the width of the parent RecyclerView
+         *
+         * @return Width in pixels
+         */
+        public int getWidth() {
+            return mWidth;
+        }
+
+        /**
+         * Return the height of the parent RecyclerView
+         *
+         * @return Height in pixels
+         */
+        public int getHeight() {
+            return mHeight;
+        }
+
+        /**
+         * Return the left padding of the parent RecyclerView
+         *
+         * @return Padding in pixels
+         */
+        public int getPaddingLeft() {
+            return mRecyclerView != null ? mRecyclerView.getPaddingLeft() : 0;
+        }
+
+        /**
+         * Return the top padding of the parent RecyclerView
+         *
+         * @return Padding in pixels
+         */
+        public int getPaddingTop() {
+            return mRecyclerView != null ? mRecyclerView.getPaddingTop() : 0;
+        }
+
+        /**
+         * Return the right padding of the parent RecyclerView
+         *
+         * @return Padding in pixels
+         */
+        public int getPaddingRight() {
+            return mRecyclerView != null ? mRecyclerView.getPaddingRight() : 0;
+        }
+
+        /**
+         * Return the bottom padding of the parent RecyclerView
+         *
+         * @return Padding in pixels
+         */
+        public int getPaddingBottom() {
+            return mRecyclerView != null ? mRecyclerView.getPaddingBottom() : 0;
+        }
+
+        /**
+         * Return the start padding of the parent RecyclerView
+         *
+         * @return Padding in pixels
+         */
+        public int getPaddingStart() {
+            return mRecyclerView != null ? mRecyclerView.getPaddingStart() : 0;
+        }
+
+        /**
+         * Return the end padding of the parent RecyclerView
+         *
+         * @return Padding in pixels
+         */
+        public int getPaddingEnd() {
+            return mRecyclerView != null ? mRecyclerView.getPaddingEnd() : 0;
+        }
+
+        /**
+         * Returns true if the RecyclerView this LayoutManager is bound to has focus.
+         *
+         * @return True if the RecyclerView has focus, false otherwise.
+         * @see View#isFocused()
+         */
+        public boolean isFocused() {
+            return mRecyclerView != null && mRecyclerView.isFocused();
+        }
+
+        /**
+         * Returns true if the RecyclerView this LayoutManager is bound to has or contains focus.
+         *
+         * @return true if the RecyclerView has or contains focus
+         * @see View#hasFocus()
+         */
+        public boolean hasFocus() {
+            return mRecyclerView != null && mRecyclerView.hasFocus();
+        }
+
+        /**
+         * Returns the item View which has or contains focus.
+         *
+         * @return A direct child of RecyclerView which has focus or contains the focused child.
+         */
+        public View getFocusedChild() {
+            if (mRecyclerView == null) {
+                return null;
+            }
+            final View focused = mRecyclerView.getFocusedChild();
+            if (focused == null || mChildHelper.isHidden(focused)) {
+                return null;
+            }
+            return focused;
+        }
+
+        /**
+         * Returns the number of items in the adapter bound to the parent RecyclerView.
+         * <p>
+         * Note that this number is not necessarily equal to
+         * {@link State#getItemCount() State#getItemCount()}. In methods where {@link State} is
+         * available, you should use {@link State#getItemCount() State#getItemCount()} instead.
+         * For more details, check the documentation for
+         * {@link State#getItemCount() State#getItemCount()}.
+         *
+         * @return The number of items in the bound adapter
+         * @see State#getItemCount()
+         */
+        public int getItemCount() {
+            final Adapter a = mRecyclerView != null ? mRecyclerView.getAdapter() : null;
+            return a != null ? a.getItemCount() : 0;
+        }
+
+        /**
+         * Offset all child views attached to the parent RecyclerView by dx pixels along
+         * the horizontal axis.
+         *
+         * @param dx Pixels to offset by
+         */
+        public void offsetChildrenHorizontal(int dx) {
+            if (mRecyclerView != null) {
+                mRecyclerView.offsetChildrenHorizontal(dx);
+            }
+        }
+
+        /**
+         * Offset all child views attached to the parent RecyclerView by dy pixels along
+         * the vertical axis.
+         *
+         * @param dy Pixels to offset by
+         */
+        public void offsetChildrenVertical(int dy) {
+            if (mRecyclerView != null) {
+                mRecyclerView.offsetChildrenVertical(dy);
+            }
+        }
+
+        /**
+         * Flags a view so that it will not be scrapped or recycled.
+         * <p>
+         * Scope of ignoring a child is strictly restricted to position tracking, scrapping and
+         * recyling. Methods like {@link #removeAndRecycleAllViews(Recycler)} will ignore the child
+         * whereas {@link #removeAllViews()} or {@link #offsetChildrenHorizontal(int)} will not
+         * ignore the child.
+         * <p>
+         * Before this child can be recycled again, you have to call
+         * {@link #stopIgnoringView(View)}.
+         * <p>
+         * You can call this method only if your LayoutManger is in onLayout or onScroll callback.
+         *
+         * @param view View to ignore.
+         * @see #stopIgnoringView(View)
+         */
+        public void ignoreView(View view) {
+            if (view.getParent() != mRecyclerView || mRecyclerView.indexOfChild(view) == -1) {
+                // checking this because calling this method on a recycled or detached view may
+                // cause loss of state.
+                throw new IllegalArgumentException("View should be fully attached to be ignored");
+            }
+            final ViewHolder vh = getChildViewHolderInt(view);
+            vh.addFlags(ViewHolder.FLAG_IGNORE);
+            mRecyclerView.mViewInfoStore.removeViewHolder(vh);
+        }
+
+        /**
+         * View can be scrapped and recycled again.
+         * <p>
+         * Note that calling this method removes all information in the view holder.
+         * <p>
+         * You can call this method only if your LayoutManger is in onLayout or onScroll callback.
+         *
+         * @param view View to ignore.
+         */
+        public void stopIgnoringView(View view) {
+            final ViewHolder vh = getChildViewHolderInt(view);
+            vh.stopIgnoring();
+            vh.resetInternal();
+            vh.addFlags(ViewHolder.FLAG_INVALID);
+        }
+
+        /**
+         * Temporarily detach and scrap all currently attached child views. Views will be scrapped
+         * into the given Recycler. The Recycler may prefer to reuse scrap views before
+         * other views that were previously recycled.
+         *
+         * @param recycler Recycler to scrap views into
+         */
+        public void detachAndScrapAttachedViews(Recycler recycler) {
+            final int childCount = getChildCount();
+            for (int i = childCount - 1; i >= 0; i--) {
+                final View v = getChildAt(i);
+                scrapOrRecycleView(recycler, i, v);
+            }
+        }
+
+        private void scrapOrRecycleView(Recycler recycler, int index, View view) {
+            final ViewHolder viewHolder = getChildViewHolderInt(view);
+            if (viewHolder.shouldIgnore()) {
+                if (DEBUG) {
+                    Log.d(TAG, "ignoring view " + viewHolder);
+                }
+                return;
+            }
+            if (viewHolder.isInvalid() && !viewHolder.isRemoved()
+                    && !mRecyclerView.mAdapter.hasStableIds()) {
+                removeViewAt(index);
+                recycler.recycleViewHolderInternal(viewHolder);
+            } else {
+                detachViewAt(index);
+                recycler.scrapView(view);
+                mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
+            }
+        }
+
+        /**
+         * Recycles the scrapped views.
+         * <p>
+         * When a view is detached and removed, it does not trigger a ViewGroup invalidate. This is
+         * the expected behavior if scrapped views are used for animations. Otherwise, we need to
+         * call remove and invalidate RecyclerView to ensure UI update.
+         *
+         * @param recycler Recycler
+         */
+        void removeAndRecycleScrapInt(Recycler recycler) {
+            final int scrapCount = recycler.getScrapCount();
+            // Loop backward, recycler might be changed by removeDetachedView()
+            for (int i = scrapCount - 1; i >= 0; i--) {
+                final View scrap = recycler.getScrapViewAt(i);
+                final ViewHolder vh = getChildViewHolderInt(scrap);
+                if (vh.shouldIgnore()) {
+                    continue;
+                }
+                // If the scrap view is animating, we need to cancel them first. If we cancel it
+                // here, ItemAnimator callback may recycle it which will cause double recycling.
+                // To avoid this, we mark it as not recycleable before calling the item animator.
+                // Since removeDetachedView calls a user API, a common mistake (ending animations on
+                // the view) may recycle it too, so we guard it before we call user APIs.
+                vh.setIsRecyclable(false);
+                if (vh.isTmpDetached()) {
+                    mRecyclerView.removeDetachedView(scrap, false);
+                }
+                if (mRecyclerView.mItemAnimator != null) {
+                    mRecyclerView.mItemAnimator.endAnimation(vh);
+                }
+                vh.setIsRecyclable(true);
+                recycler.quickRecycleScrapView(scrap);
+            }
+            recycler.clearScrap();
+            if (scrapCount > 0) {
+                mRecyclerView.invalidate();
+            }
+        }
+
+
+        /**
+         * Measure a child view using standard measurement policy, taking the padding
+         * of the parent RecyclerView and any added item decorations into account.
+         *
+         * <p>If the RecyclerView can be scrolled in either dimension the caller may
+         * pass 0 as the widthUsed or heightUsed parameters as they will be irrelevant.</p>
+         *
+         * @param child Child view to measure
+         * @param widthUsed Width in pixels currently consumed by other views, if relevant
+         * @param heightUsed Height in pixels currently consumed by other views, if relevant
+         */
+        public void measureChild(View child, int widthUsed, int heightUsed) {
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
+            widthUsed += insets.left + insets.right;
+            heightUsed += insets.top + insets.bottom;
+            final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),
+                    getPaddingLeft() + getPaddingRight() + widthUsed, lp.width,
+                    canScrollHorizontally());
+            final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(),
+                    getPaddingTop() + getPaddingBottom() + heightUsed, lp.height,
+                    canScrollVertically());
+            if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) {
+                child.measure(widthSpec, heightSpec);
+            }
+        }
+
+        /**
+         * RecyclerView internally does its own View measurement caching which should help with
+         * WRAP_CONTENT.
+         * <p>
+         * Use this method if the View is already measured once in this layout pass.
+         */
+        boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec, LayoutParams lp) {
+            return !mMeasurementCacheEnabled
+                    || !isMeasurementUpToDate(child.getMeasuredWidth(), widthSpec, lp.width)
+                    || !isMeasurementUpToDate(child.getMeasuredHeight(), heightSpec, lp.height);
+        }
+
+        // we may consider making this public
+        /**
+         * RecyclerView internally does its own View measurement caching which should help with
+         * WRAP_CONTENT.
+         * <p>
+         * Use this method if the View is not yet measured and you need to decide whether to
+         * measure this View or not.
+         */
+        boolean shouldMeasureChild(View child, int widthSpec, int heightSpec, LayoutParams lp) {
+            return child.isLayoutRequested()
+                    || !mMeasurementCacheEnabled
+                    || !isMeasurementUpToDate(child.getWidth(), widthSpec, lp.width)
+                    || !isMeasurementUpToDate(child.getHeight(), heightSpec, lp.height);
+        }
+
+        /**
+         * In addition to the View Framework's measurement cache, RecyclerView uses its own
+         * additional measurement cache for its children to avoid re-measuring them when not
+         * necessary. It is on by default but it can be turned off via
+         * {@link #setMeasurementCacheEnabled(boolean)}.
+         *
+         * @return True if measurement cache is enabled, false otherwise.
+         *
+         * @see #setMeasurementCacheEnabled(boolean)
+         */
+        public boolean isMeasurementCacheEnabled() {
+            return mMeasurementCacheEnabled;
+        }
+
+        /**
+         * Sets whether RecyclerView should use its own measurement cache for the children. This is
+         * a more aggressive cache than the framework uses.
+         *
+         * @param measurementCacheEnabled True to enable the measurement cache, false otherwise.
+         *
+         * @see #isMeasurementCacheEnabled()
+         */
+        public void setMeasurementCacheEnabled(boolean measurementCacheEnabled) {
+            mMeasurementCacheEnabled = measurementCacheEnabled;
+        }
+
+        private static boolean isMeasurementUpToDate(int childSize, int spec, int dimension) {
+            final int specMode = MeasureSpec.getMode(spec);
+            final int specSize = MeasureSpec.getSize(spec);
+            if (dimension > 0 && childSize != dimension) {
+                return false;
+            }
+            switch (specMode) {
+                case MeasureSpec.UNSPECIFIED:
+                    return true;
+                case MeasureSpec.AT_MOST:
+                    return specSize >= childSize;
+                case MeasureSpec.EXACTLY:
+                    return  specSize == childSize;
+            }
+            return false;
+        }
+
+        /**
+         * Measure a child view using standard measurement policy, taking the padding
+         * of the parent RecyclerView, any added item decorations and the child margins
+         * into account.
+         *
+         * <p>If the RecyclerView can be scrolled in either dimension the caller may
+         * pass 0 as the widthUsed or heightUsed parameters as they will be irrelevant.</p>
+         *
+         * @param child Child view to measure
+         * @param widthUsed Width in pixels currently consumed by other views, if relevant
+         * @param heightUsed Height in pixels currently consumed by other views, if relevant
+         */
+        public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
+            widthUsed += insets.left + insets.right;
+            heightUsed += insets.top + insets.bottom;
+
+            final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),
+                    getPaddingLeft() + getPaddingRight()
+                            + lp.leftMargin + lp.rightMargin + widthUsed, lp.width,
+                    canScrollHorizontally());
+            final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(),
+                    getPaddingTop() + getPaddingBottom()
+                            + lp.topMargin + lp.bottomMargin + heightUsed, lp.height,
+                    canScrollVertically());
+            if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) {
+                child.measure(widthSpec, heightSpec);
+            }
+        }
+
+        /**
+         * Calculate a MeasureSpec value for measuring a child view in one dimension.
+         *
+         * @param parentSize Size of the parent view where the child will be placed
+         * @param padding Total space currently consumed by other elements of the parent
+         * @param childDimension Desired size of the child view, or MATCH_PARENT/WRAP_CONTENT.
+         *                       Generally obtained from the child view's LayoutParams
+         * @param canScroll true if the parent RecyclerView can scroll in this dimension
+         *
+         * @return a MeasureSpec value for the child view
+         * @deprecated use {@link #getChildMeasureSpec(int, int, int, int, boolean)}
+         */
+        @Deprecated
+        public static int getChildMeasureSpec(int parentSize, int padding, int childDimension,
+                boolean canScroll) {
+            int size = Math.max(0, parentSize - padding);
+            int resultSize = 0;
+            int resultMode = 0;
+            if (canScroll) {
+                if (childDimension >= 0) {
+                    resultSize = childDimension;
+                    resultMode = MeasureSpec.EXACTLY;
+                } else {
+                    // MATCH_PARENT can't be applied since we can scroll in this dimension, wrap
+                    // instead using UNSPECIFIED.
+                    resultSize = 0;
+                    resultMode = MeasureSpec.UNSPECIFIED;
+                }
+            } else {
+                if (childDimension >= 0) {
+                    resultSize = childDimension;
+                    resultMode = MeasureSpec.EXACTLY;
+                } else if (childDimension == LayoutParams.MATCH_PARENT) {
+                    resultSize = size;
+                    // TODO this should be my spec.
+                    resultMode = MeasureSpec.EXACTLY;
+                } else if (childDimension == LayoutParams.WRAP_CONTENT) {
+                    resultSize = size;
+                    resultMode = MeasureSpec.AT_MOST;
+                }
+            }
+            return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
+        }
+
+        /**
+         * Calculate a MeasureSpec value for measuring a child view in one dimension.
+         *
+         * @param parentSize Size of the parent view where the child will be placed
+         * @param parentMode The measurement spec mode of the parent
+         * @param padding Total space currently consumed by other elements of parent
+         * @param childDimension Desired size of the child view, or MATCH_PARENT/WRAP_CONTENT.
+         *                       Generally obtained from the child view's LayoutParams
+         * @param canScroll true if the parent RecyclerView can scroll in this dimension
+         *
+         * @return a MeasureSpec value for the child view
+         */
+        public static int getChildMeasureSpec(int parentSize, int parentMode, int padding,
+                int childDimension, boolean canScroll) {
+            int size = Math.max(0, parentSize - padding);
+            int resultSize = 0;
+            int resultMode = 0;
+            if (canScroll) {
+                if (childDimension >= 0) {
+                    resultSize = childDimension;
+                    resultMode = MeasureSpec.EXACTLY;
+                } else if (childDimension == LayoutParams.MATCH_PARENT) {
+                    switch (parentMode) {
+                        case MeasureSpec.AT_MOST:
+                        case MeasureSpec.EXACTLY:
+                            resultSize = size;
+                            resultMode = parentMode;
+                            break;
+                        case MeasureSpec.UNSPECIFIED:
+                            resultSize = 0;
+                            resultMode = MeasureSpec.UNSPECIFIED;
+                            break;
+                    }
+                } else if (childDimension == LayoutParams.WRAP_CONTENT) {
+                    resultSize = 0;
+                    resultMode = MeasureSpec.UNSPECIFIED;
+                }
+            } else {
+                if (childDimension >= 0) {
+                    resultSize = childDimension;
+                    resultMode = MeasureSpec.EXACTLY;
+                } else if (childDimension == LayoutParams.MATCH_PARENT) {
+                    resultSize = size;
+                    resultMode = parentMode;
+                } else if (childDimension == LayoutParams.WRAP_CONTENT) {
+                    resultSize = size;
+                    if (parentMode == MeasureSpec.AT_MOST || parentMode == MeasureSpec.EXACTLY) {
+                        resultMode = MeasureSpec.AT_MOST;
+                    } else {
+                        resultMode = MeasureSpec.UNSPECIFIED;
+                    }
+
+                }
+            }
+            //noinspection WrongConstant
+            return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
+        }
+
+        /**
+         * Returns the measured width of the given child, plus the additional size of
+         * any insets applied by {@link ItemDecoration ItemDecorations}.
+         *
+         * @param child Child view to query
+         * @return child's measured width plus <code>ItemDecoration</code> insets
+         *
+         * @see View#getMeasuredWidth()
+         */
+        public int getDecoratedMeasuredWidth(View child) {
+            final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets;
+            return child.getMeasuredWidth() + insets.left + insets.right;
+        }
+
+        /**
+         * Returns the measured height of the given child, plus the additional size of
+         * any insets applied by {@link ItemDecoration ItemDecorations}.
+         *
+         * @param child Child view to query
+         * @return child's measured height plus <code>ItemDecoration</code> insets
+         *
+         * @see View#getMeasuredHeight()
+         */
+        public int getDecoratedMeasuredHeight(View child) {
+            final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets;
+            return child.getMeasuredHeight() + insets.top + insets.bottom;
+        }
+
+        /**
+         * Lay out the given child view within the RecyclerView using coordinates that
+         * include any current {@link ItemDecoration ItemDecorations}.
+         *
+         * <p>LayoutManagers should prefer working in sizes and coordinates that include
+         * item decoration insets whenever possible. This allows the LayoutManager to effectively
+         * ignore decoration insets within measurement and layout code. See the following
+         * methods:</p>
+         * <ul>
+         *     <li>{@link #layoutDecoratedWithMargins(View, int, int, int, int)}</li>
+         *     <li>{@link #getDecoratedBoundsWithMargins(View, Rect)}</li>
+         *     <li>{@link #measureChild(View, int, int)}</li>
+         *     <li>{@link #measureChildWithMargins(View, int, int)}</li>
+         *     <li>{@link #getDecoratedLeft(View)}</li>
+         *     <li>{@link #getDecoratedTop(View)}</li>
+         *     <li>{@link #getDecoratedRight(View)}</li>
+         *     <li>{@link #getDecoratedBottom(View)}</li>
+         *     <li>{@link #getDecoratedMeasuredWidth(View)}</li>
+         *     <li>{@link #getDecoratedMeasuredHeight(View)}</li>
+         * </ul>
+         *
+         * @param child Child to lay out
+         * @param left Left edge, with item decoration insets included
+         * @param top Top edge, with item decoration insets included
+         * @param right Right edge, with item decoration insets included
+         * @param bottom Bottom edge, with item decoration insets included
+         *
+         * @see View#layout(int, int, int, int)
+         * @see #layoutDecoratedWithMargins(View, int, int, int, int)
+         */
+        public void layoutDecorated(View child, int left, int top, int right, int bottom) {
+            final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets;
+            child.layout(left + insets.left, top + insets.top, right - insets.right,
+                    bottom - insets.bottom);
+        }
+
+        /**
+         * Lay out the given child view within the RecyclerView using coordinates that
+         * include any current {@link ItemDecoration ItemDecorations} and margins.
+         *
+         * <p>LayoutManagers should prefer working in sizes and coordinates that include
+         * item decoration insets whenever possible. This allows the LayoutManager to effectively
+         * ignore decoration insets within measurement and layout code. See the following
+         * methods:</p>
+         * <ul>
+         *     <li>{@link #layoutDecorated(View, int, int, int, int)}</li>
+         *     <li>{@link #measureChild(View, int, int)}</li>
+         *     <li>{@link #measureChildWithMargins(View, int, int)}</li>
+         *     <li>{@link #getDecoratedLeft(View)}</li>
+         *     <li>{@link #getDecoratedTop(View)}</li>
+         *     <li>{@link #getDecoratedRight(View)}</li>
+         *     <li>{@link #getDecoratedBottom(View)}</li>
+         *     <li>{@link #getDecoratedMeasuredWidth(View)}</li>
+         *     <li>{@link #getDecoratedMeasuredHeight(View)}</li>
+         * </ul>
+         *
+         * @param child Child to lay out
+         * @param left Left edge, with item decoration insets and left margin included
+         * @param top Top edge, with item decoration insets and top margin included
+         * @param right Right edge, with item decoration insets and right margin included
+         * @param bottom Bottom edge, with item decoration insets and bottom margin included
+         *
+         * @see View#layout(int, int, int, int)
+         * @see #layoutDecorated(View, int, int, int, int)
+         */
+        public void layoutDecoratedWithMargins(View child, int left, int top, int right,
+                int bottom) {
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final Rect insets = lp.mDecorInsets;
+            child.layout(left + insets.left + lp.leftMargin, top + insets.top + lp.topMargin,
+                    right - insets.right - lp.rightMargin,
+                    bottom - insets.bottom - lp.bottomMargin);
+        }
+
+        /**
+         * Calculates the bounding box of the View while taking into account its matrix changes
+         * (translation, scale etc) with respect to the RecyclerView.
+         * <p>
+         * If {@code includeDecorInsets} is {@code true}, they are applied first before applying
+         * the View's matrix so that the decor offsets also go through the same transformation.
+         *
+         * @param child The ItemView whose bounding box should be calculated.
+         * @param includeDecorInsets True if the decor insets should be included in the bounding box
+         * @param out The rectangle into which the output will be written.
+         */
+        public void getTransformedBoundingBox(View child, boolean includeDecorInsets, Rect out) {
+            if (includeDecorInsets) {
+                Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets;
+                out.set(-insets.left, -insets.top,
+                        child.getWidth() + insets.right, child.getHeight() + insets.bottom);
+            } else {
+                out.set(0, 0, child.getWidth(), child.getHeight());
+            }
+
+            if (mRecyclerView != null) {
+                final Matrix childMatrix = child.getMatrix();
+                if (childMatrix != null && !childMatrix.isIdentity()) {
+                    final RectF tempRectF = mRecyclerView.mTempRectF;
+                    tempRectF.set(out);
+                    childMatrix.mapRect(tempRectF);
+                    out.set(
+                            (int) Math.floor(tempRectF.left),
+                            (int) Math.floor(tempRectF.top),
+                            (int) Math.ceil(tempRectF.right),
+                            (int) Math.ceil(tempRectF.bottom)
+                    );
+                }
+            }
+            out.offset(child.getLeft(), child.getTop());
+        }
+
+        /**
+         * Returns the bounds of the view including its decoration and margins.
+         *
+         * @param view The view element to check
+         * @param outBounds A rect that will receive the bounds of the element including its
+         *                  decoration and margins.
+         */
+        public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
+            RecyclerView.getDecoratedBoundsWithMarginsInt(view, outBounds);
+        }
+
+        /**
+         * Returns the left edge of the given child view within its parent, offset by any applied
+         * {@link ItemDecoration ItemDecorations}.
+         *
+         * @param child Child to query
+         * @return Child left edge with offsets applied
+         * @see #getLeftDecorationWidth(View)
+         */
+        public int getDecoratedLeft(View child) {
+            return child.getLeft() - getLeftDecorationWidth(child);
+        }
+
+        /**
+         * Returns the top edge of the given child view within its parent, offset by any applied
+         * {@link ItemDecoration ItemDecorations}.
+         *
+         * @param child Child to query
+         * @return Child top edge with offsets applied
+         * @see #getTopDecorationHeight(View)
+         */
+        public int getDecoratedTop(View child) {
+            return child.getTop() - getTopDecorationHeight(child);
+        }
+
+        /**
+         * Returns the right edge of the given child view within its parent, offset by any applied
+         * {@link ItemDecoration ItemDecorations}.
+         *
+         * @param child Child to query
+         * @return Child right edge with offsets applied
+         * @see #getRightDecorationWidth(View)
+         */
+        public int getDecoratedRight(View child) {
+            return child.getRight() + getRightDecorationWidth(child);
+        }
+
+        /**
+         * Returns the bottom edge of the given child view within its parent, offset by any applied
+         * {@link ItemDecoration ItemDecorations}.
+         *
+         * @param child Child to query
+         * @return Child bottom edge with offsets applied
+         * @see #getBottomDecorationHeight(View)
+         */
+        public int getDecoratedBottom(View child) {
+            return child.getBottom() + getBottomDecorationHeight(child);
+        }
+
+        /**
+         * Calculates the item decor insets applied to the given child and updates the provided
+         * Rect instance with the inset values.
+         * <ul>
+         *     <li>The Rect's left is set to the total width of left decorations.</li>
+         *     <li>The Rect's top is set to the total height of top decorations.</li>
+         *     <li>The Rect's right is set to the total width of right decorations.</li>
+         *     <li>The Rect's bottom is set to total height of bottom decorations.</li>
+         * </ul>
+         * <p>
+         * Note that item decorations are automatically calculated when one of the LayoutManager's
+         * measure child methods is called. If you need to measure the child with custom specs via
+         * {@link View#measure(int, int)}, you can use this method to get decorations.
+         *
+         * @param child The child view whose decorations should be calculated
+         * @param outRect The Rect to hold result values
+         */
+        public void calculateItemDecorationsForChild(View child, Rect outRect) {
+            if (mRecyclerView == null) {
+                outRect.set(0, 0, 0, 0);
+                return;
+            }
+            Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
+            outRect.set(insets);
+        }
+
+        /**
+         * Returns the total height of item decorations applied to child's top.
+         * <p>
+         * Note that this value is not updated until the View is measured or
+         * {@link #calculateItemDecorationsForChild(View, Rect)} is called.
+         *
+         * @param child Child to query
+         * @return The total height of item decorations applied to the child's top.
+         * @see #getDecoratedTop(View)
+         * @see #calculateItemDecorationsForChild(View, Rect)
+         */
+        public int getTopDecorationHeight(View child) {
+            return ((LayoutParams) child.getLayoutParams()).mDecorInsets.top;
+        }
+
+        /**
+         * Returns the total height of item decorations applied to child's bottom.
+         * <p>
+         * Note that this value is not updated until the View is measured or
+         * {@link #calculateItemDecorationsForChild(View, Rect)} is called.
+         *
+         * @param child Child to query
+         * @return The total height of item decorations applied to the child's bottom.
+         * @see #getDecoratedBottom(View)
+         * @see #calculateItemDecorationsForChild(View, Rect)
+         */
+        public int getBottomDecorationHeight(View child) {
+            return ((LayoutParams) child.getLayoutParams()).mDecorInsets.bottom;
+        }
+
+        /**
+         * Returns the total width of item decorations applied to child's left.
+         * <p>
+         * Note that this value is not updated until the View is measured or
+         * {@link #calculateItemDecorationsForChild(View, Rect)} is called.
+         *
+         * @param child Child to query
+         * @return The total width of item decorations applied to the child's left.
+         * @see #getDecoratedLeft(View)
+         * @see #calculateItemDecorationsForChild(View, Rect)
+         */
+        public int getLeftDecorationWidth(View child) {
+            return ((LayoutParams) child.getLayoutParams()).mDecorInsets.left;
+        }
+
+        /**
+         * Returns the total width of item decorations applied to child's right.
+         * <p>
+         * Note that this value is not updated until the View is measured or
+         * {@link #calculateItemDecorationsForChild(View, Rect)} is called.
+         *
+         * @param child Child to query
+         * @return The total width of item decorations applied to the child's right.
+         * @see #getDecoratedRight(View)
+         * @see #calculateItemDecorationsForChild(View, Rect)
+         */
+        public int getRightDecorationWidth(View child) {
+            return ((LayoutParams) child.getLayoutParams()).mDecorInsets.right;
+        }
+
+        /**
+         * Called when searching for a focusable view in the given direction has failed
+         * for the current content of the RecyclerView.
+         *
+         * <p>This is the LayoutManager's opportunity to populate views in the given direction
+         * to fulfill the request if it can. The LayoutManager should attach and return
+         * the view to be focused. The default implementation returns null.</p>
+         *
+         * @param focused   The currently focused view
+         * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+         *                  {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
+         *                  {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
+         *                  or 0 for not applicable
+         * @param recycler  The recycler to use for obtaining views for currently offscreen items
+         * @param state     Transient state of RecyclerView
+         * @return The chosen view to be focused
+         */
+        @Nullable
+        public View onFocusSearchFailed(View focused, int direction, Recycler recycler,
+                State state) {
+            return null;
+        }
+
+        /**
+         * This method gives a LayoutManager an opportunity to intercept the initial focus search
+         * before the default behavior of {@link FocusFinder} is used. If this method returns
+         * null FocusFinder will attempt to find a focusable child view. If it fails
+         * then {@link #onFocusSearchFailed(View, int, RecyclerView.Recycler, RecyclerView.State)}
+         * will be called to give the LayoutManager an opportunity to add new views for items
+         * that did not have attached views representing them. The LayoutManager should not add
+         * or remove views from this method.
+         *
+         * @param focused The currently focused view
+         * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+         *                  {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
+         *                  {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
+         * @return A descendant view to focus or null to fall back to default behavior.
+         *         The default implementation returns null.
+         */
+        public View onInterceptFocusSearch(View focused, int direction) {
+            return null;
+        }
+
+        /**
+         * Called when a child of the RecyclerView wants a particular rectangle to be positioned
+         * onto the screen. See {@link ViewParent#requestChildRectangleOnScreen(android.view.View,
+         * android.graphics.Rect, boolean)} for more details.
+         *
+         * <p>The base implementation will attempt to perform a standard programmatic scroll
+         * to bring the given rect into view, within the padded area of the RecyclerView.</p>
+         *
+         * @param child The direct child making the request.
+         * @param rect  The rectangle in the child's coordinates the child
+         *              wishes to be on the screen.
+         * @param immediate True to forbid animated or delayed scrolling,
+         *                  false otherwise
+         * @return Whether the group scrolled to handle the operation
+         */
+        public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect,
+                boolean immediate) {
+            final int parentLeft = getPaddingLeft();
+            final int parentTop = getPaddingTop();
+            final int parentRight = getWidth() - getPaddingRight();
+            final int parentBottom = getHeight() - getPaddingBottom();
+            final int childLeft = child.getLeft() + rect.left - child.getScrollX();
+            final int childTop = child.getTop() + rect.top - child.getScrollY();
+            final int childRight = childLeft + rect.width();
+            final int childBottom = childTop + rect.height();
+
+            final int offScreenLeft = Math.min(0, childLeft - parentLeft);
+            final int offScreenTop = Math.min(0, childTop - parentTop);
+            final int offScreenRight = Math.max(0, childRight - parentRight);
+            final int offScreenBottom = Math.max(0, childBottom - parentBottom);
+
+            // Favor the "start" layout direction over the end when bringing one side or the other
+            // of a large rect into view. If we decide to bring in end because start is already
+            // visible, limit the scroll such that start won't go out of bounds.
+            final int dx;
+            if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+                dx = offScreenRight != 0 ? offScreenRight
+                        : Math.max(offScreenLeft, childRight - parentRight);
+            } else {
+                dx = offScreenLeft != 0 ? offScreenLeft
+                        : Math.min(childLeft - parentLeft, offScreenRight);
+            }
+
+            // Favor bringing the top into view over the bottom. If top is already visible and
+            // we should scroll to make bottom visible, make sure top does not go out of bounds.
+            final int dy = offScreenTop != 0 ? offScreenTop
+                    : Math.min(childTop - parentTop, offScreenBottom);
+
+            if (dx != 0 || dy != 0) {
+                if (immediate) {
+                    parent.scrollBy(dx, dy);
+                } else {
+                    parent.smoothScrollBy(dx, dy);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * @deprecated Use {@link #onRequestChildFocus(RecyclerView, State, View, View)}
+         */
+        @Deprecated
+        public boolean onRequestChildFocus(RecyclerView parent, View child, View focused) {
+            // eat the request if we are in the middle of a scroll or layout
+            return isSmoothScrolling() || parent.isComputingLayout();
+        }
+
+        /**
+         * Called when a descendant view of the RecyclerView requests focus.
+         *
+         * <p>A LayoutManager wishing to keep focused views aligned in a specific
+         * portion of the view may implement that behavior in an override of this method.</p>
+         *
+         * <p>If the LayoutManager executes different behavior that should override the default
+         * behavior of scrolling the focused child on screen instead of running alongside it,
+         * this method should return true.</p>
+         *
+         * @param parent  The RecyclerView hosting this LayoutManager
+         * @param state   Current state of RecyclerView
+         * @param child   Direct child of the RecyclerView containing the newly focused view
+         * @param focused The newly focused view. This may be the same view as child or it may be
+         *                null
+         * @return true if the default scroll behavior should be suppressed
+         */
+        public boolean onRequestChildFocus(RecyclerView parent, State state, View child,
+                View focused) {
+            return onRequestChildFocus(parent, child, focused);
+        }
+
+        /**
+         * Called if the RecyclerView this LayoutManager is bound to has a different adapter set.
+         * The LayoutManager may use this opportunity to clear caches and configure state such
+         * that it can relayout appropriately with the new data and potentially new view types.
+         *
+         * <p>The default implementation removes all currently attached views.</p>
+         *
+         * @param oldAdapter The previous adapter instance. Will be null if there was previously no
+         *                   adapter.
+         * @param newAdapter The new adapter instance. Might be null if
+         *                   {@link #setAdapter(RecyclerView.Adapter)} is called with {@code null}.
+         */
+        public void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter) {
+        }
+
+        /**
+         * Called to populate focusable views within the RecyclerView.
+         *
+         * <p>The LayoutManager implementation should return <code>true</code> if the default
+         * behavior of {@link ViewGroup#addFocusables(java.util.ArrayList, int)} should be
+         * suppressed.</p>
+         *
+         * <p>The default implementation returns <code>false</code> to trigger RecyclerView
+         * to fall back to the default ViewGroup behavior.</p>
+         *
+         * @param recyclerView The RecyclerView hosting this LayoutManager
+         * @param views List of output views. This method should add valid focusable views
+         *              to this list.
+         * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
+         *                  {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT},
+         *                  {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD}
+         * @param focusableMode The type of focusables to be added.
+         *
+         * @return true to suppress the default behavior, false to add default focusables after
+         *         this method returns.
+         *
+         * @see #FOCUSABLES_ALL
+         * @see #FOCUSABLES_TOUCH_MODE
+         */
+        public boolean onAddFocusables(RecyclerView recyclerView, ArrayList<View> views,
+                int direction, int focusableMode) {
+            return false;
+        }
+
+        /**
+         * Called when {@link Adapter#notifyDataSetChanged()} is triggered instead of giving
+         * detailed information on what has actually changed.
+         *
+         * @param recyclerView
+         */
+        public void onItemsChanged(RecyclerView recyclerView) {
+        }
+
+        /**
+         * Called when items have been added to the adapter. The LayoutManager may choose to
+         * requestLayout if the inserted items would require refreshing the currently visible set
+         * of child views. (e.g. currently empty space would be filled by appended items, etc.)
+         *
+         * @param recyclerView
+         * @param positionStart
+         * @param itemCount
+         */
+        public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
+        }
+
+        /**
+         * Called when items have been removed from the adapter.
+         *
+         * @param recyclerView
+         * @param positionStart
+         * @param itemCount
+         */
+        public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
+        }
+
+        /**
+         * Called when items have been changed in the adapter.
+         * To receive payload,  override {@link #onItemsUpdated(RecyclerView, int, int, Object)}
+         * instead, then this callback will not be invoked.
+         *
+         * @param recyclerView
+         * @param positionStart
+         * @param itemCount
+         */
+        public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
+        }
+
+        /**
+         * Called when items have been changed in the adapter and with optional payload.
+         * Default implementation calls {@link #onItemsUpdated(RecyclerView, int, int)}.
+         *
+         * @param recyclerView
+         * @param positionStart
+         * @param itemCount
+         * @param payload
+         */
+        public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount,
+                Object payload) {
+            onItemsUpdated(recyclerView, positionStart, itemCount);
+        }
+
+        /**
+         * Called when an item is moved withing the adapter.
+         * <p>
+         * Note that, an item may also change position in response to another ADD/REMOVE/MOVE
+         * operation. This callback is only called if and only if {@link Adapter#notifyItemMoved}
+         * is called.
+         *
+         * @param recyclerView
+         * @param from
+         * @param to
+         * @param itemCount
+         */
+        public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
+
+        }
+
+
+        /**
+         * <p>Override this method if you want to support scroll bars.</p>
+         *
+         * <p>Read {@link RecyclerView#computeHorizontalScrollExtent()} for details.</p>
+         *
+         * <p>Default implementation returns 0.</p>
+         *
+         * @param state Current state of RecyclerView
+         * @return The horizontal extent of the scrollbar's thumb
+         * @see RecyclerView#computeHorizontalScrollExtent()
+         */
+        public int computeHorizontalScrollExtent(State state) {
+            return 0;
+        }
+
+        /**
+         * <p>Override this method if you want to support scroll bars.</p>
+         *
+         * <p>Read {@link RecyclerView#computeHorizontalScrollOffset()} for details.</p>
+         *
+         * <p>Default implementation returns 0.</p>
+         *
+         * @param state Current State of RecyclerView where you can find total item count
+         * @return The horizontal offset of the scrollbar's thumb
+         * @see RecyclerView#computeHorizontalScrollOffset()
+         */
+        public int computeHorizontalScrollOffset(State state) {
+            return 0;
+        }
+
+        /**
+         * <p>Override this method if you want to support scroll bars.</p>
+         *
+         * <p>Read {@link RecyclerView#computeHorizontalScrollRange()} for details.</p>
+         *
+         * <p>Default implementation returns 0.</p>
+         *
+         * @param state Current State of RecyclerView where you can find total item count
+         * @return The total horizontal range represented by the vertical scrollbar
+         * @see RecyclerView#computeHorizontalScrollRange()
+         */
+        public int computeHorizontalScrollRange(State state) {
+            return 0;
+        }
+
+        /**
+         * <p>Override this method if you want to support scroll bars.</p>
+         *
+         * <p>Read {@link RecyclerView#computeVerticalScrollExtent()} for details.</p>
+         *
+         * <p>Default implementation returns 0.</p>
+         *
+         * @param state Current state of RecyclerView
+         * @return The vertical extent of the scrollbar's thumb
+         * @see RecyclerView#computeVerticalScrollExtent()
+         */
+        public int computeVerticalScrollExtent(State state) {
+            return 0;
+        }
+
+        /**
+         * <p>Override this method if you want to support scroll bars.</p>
+         *
+         * <p>Read {@link RecyclerView#computeVerticalScrollOffset()} for details.</p>
+         *
+         * <p>Default implementation returns 0.</p>
+         *
+         * @param state Current State of RecyclerView where you can find total item count
+         * @return The vertical offset of the scrollbar's thumb
+         * @see RecyclerView#computeVerticalScrollOffset()
+         */
+        public int computeVerticalScrollOffset(State state) {
+            return 0;
+        }
+
+        /**
+         * <p>Override this method if you want to support scroll bars.</p>
+         *
+         * <p>Read {@link RecyclerView#computeVerticalScrollRange()} for details.</p>
+         *
+         * <p>Default implementation returns 0.</p>
+         *
+         * @param state Current State of RecyclerView where you can find total item count
+         * @return The total vertical range represented by the vertical scrollbar
+         * @see RecyclerView#computeVerticalScrollRange()
+         */
+        public int computeVerticalScrollRange(State state) {
+            return 0;
+        }
+
+        /**
+         * Measure the attached RecyclerView. Implementations must call
+         * {@link #setMeasuredDimension(int, int)} before returning.
+         *
+         * <p>The default implementation will handle EXACTLY measurements and respect
+         * the minimum width and height properties of the host RecyclerView if measured
+         * as UNSPECIFIED. AT_MOST measurements will be treated as EXACTLY and the RecyclerView
+         * will consume all available space.</p>
+         *
+         * @param recycler Recycler
+         * @param state Transient state of RecyclerView
+         * @param widthSpec Width {@link android.view.View.MeasureSpec}
+         * @param heightSpec Height {@link android.view.View.MeasureSpec}
+         */
+        public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) {
+            mRecyclerView.defaultOnMeasure(widthSpec, heightSpec);
+        }
+
+        /**
+         * {@link View#setMeasuredDimension(int, int) Set the measured dimensions} of the
+         * host RecyclerView.
+         *
+         * @param widthSize Measured width
+         * @param heightSize Measured height
+         */
+        public void setMeasuredDimension(int widthSize, int heightSize) {
+            mRecyclerView.setMeasuredDimension(widthSize, heightSize);
+        }
+
+        /**
+         * @return The host RecyclerView's {@link View#getMinimumWidth()}
+         */
+        public int getMinimumWidth() {
+            return mRecyclerView.getMinimumWidth();
+        }
+
+        /**
+         * @return The host RecyclerView's {@link View#getMinimumHeight()}
+         */
+        public int getMinimumHeight() {
+            return mRecyclerView.getMinimumHeight();
+        }
+        /**
+         * <p>Called when the LayoutManager should save its state. This is a good time to save your
+         * scroll position, configuration and anything else that may be required to restore the same
+         * layout state if the LayoutManager is recreated.</p>
+         * <p>RecyclerView does NOT verify if the LayoutManager has changed between state save and
+         * restore. This will let you share information between your LayoutManagers but it is also
+         * your responsibility to make sure they use the same parcelable class.</p>
+         *
+         * @return Necessary information for LayoutManager to be able to restore its state
+         */
+        public Parcelable onSaveInstanceState() {
+            return null;
+        }
+
+
+        public void onRestoreInstanceState(Parcelable state) {
+
+        }
+
+        void stopSmoothScroller() {
+            if (mSmoothScroller != null) {
+                mSmoothScroller.stop();
+            }
+        }
+
+        private void onSmoothScrollerStopped(SmoothScroller smoothScroller) {
+            if (mSmoothScroller == smoothScroller) {
+                mSmoothScroller = null;
+            }
+        }
+
+        /**
+         * RecyclerView calls this method to notify LayoutManager that scroll state has changed.
+         *
+         * @param state The new scroll state for RecyclerView
+         */
+        public void onScrollStateChanged(int state) {
+        }
+
+        /**
+         * Removes all views and recycles them using the given recycler.
+         * <p>
+         * If you want to clean cached views as well, you should call {@link Recycler#clear()} too.
+         * <p>
+         * If a View is marked as "ignored", it is not removed nor recycled.
+         *
+         * @param recycler Recycler to use to recycle children
+         * @see #removeAndRecycleView(View, Recycler)
+         * @see #removeAndRecycleViewAt(int, Recycler)
+         * @see #ignoreView(View)
+         */
+        public void removeAndRecycleAllViews(Recycler recycler) {
+            for (int i = getChildCount() - 1; i >= 0; i--) {
+                final View view = getChildAt(i);
+                if (!getChildViewHolderInt(view).shouldIgnore()) {
+                    removeAndRecycleViewAt(i, recycler);
+                }
+            }
+        }
+
+        // called by accessibility delegate
+        void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+            onInitializeAccessibilityNodeInfo(mRecyclerView.mRecycler, mRecyclerView.mState, info);
+        }
+
+        /**
+         * Called by the AccessibilityDelegate when the information about the current layout should
+         * be populated.
+         * <p>
+         * Default implementation adds a {@link
+         * android.view.accessibility.AccessibilityNodeInfo.CollectionInfo}.
+         * <p>
+         * You should override
+         * {@link #getRowCountForAccessibility(RecyclerView.Recycler, RecyclerView.State)},
+         * {@link #getColumnCountForAccessibility(RecyclerView.Recycler, RecyclerView.State)},
+         * {@link #isLayoutHierarchical(RecyclerView.Recycler, RecyclerView.State)} and
+         * {@link #getSelectionModeForAccessibility(RecyclerView.Recycler, RecyclerView.State)} for
+         * more accurate accessibility information.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @param info     The info that should be filled by the LayoutManager
+         * @see View#onInitializeAccessibilityNodeInfo(
+         *android.view.accessibility.AccessibilityNodeInfo)
+         * @see #getRowCountForAccessibility(RecyclerView.Recycler, RecyclerView.State)
+         * @see #getColumnCountForAccessibility(RecyclerView.Recycler, RecyclerView.State)
+         * @see #isLayoutHierarchical(RecyclerView.Recycler, RecyclerView.State)
+         * @see #getSelectionModeForAccessibility(RecyclerView.Recycler, RecyclerView.State)
+         */
+        public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state,
+                AccessibilityNodeInfo info) {
+            if (mRecyclerView.canScrollVertically(-1)
+                    || mRecyclerView.canScrollHorizontally(-1)) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+                info.setScrollable(true);
+            }
+            if (mRecyclerView.canScrollVertically(1)
+                    || mRecyclerView.canScrollHorizontally(1)) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+                info.setScrollable(true);
+            }
+            final AccessibilityNodeInfo.CollectionInfo collectionInfo =
+                    AccessibilityNodeInfo.CollectionInfo
+                            .obtain(getRowCountForAccessibility(recycler, state),
+                                    getColumnCountForAccessibility(recycler, state),
+                                    isLayoutHierarchical(recycler, state),
+                                    getSelectionModeForAccessibility(recycler, state));
+            info.setCollectionInfo(collectionInfo);
+        }
+
+        // called by accessibility delegate
+        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+            onInitializeAccessibilityEvent(mRecyclerView.mRecycler, mRecyclerView.mState, event);
+        }
+
+        /**
+         * Called by the accessibility delegate to initialize an accessibility event.
+         * <p>
+         * Default implementation adds item count and scroll information to the event.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @param event    The event instance to initialize
+         * @see View#onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent)
+         */
+        public void onInitializeAccessibilityEvent(Recycler recycler, State state,
+                AccessibilityEvent event) {
+            if (mRecyclerView == null || event == null) {
+                return;
+            }
+            event.setScrollable(mRecyclerView.canScrollVertically(1)
+                    || mRecyclerView.canScrollVertically(-1)
+                    || mRecyclerView.canScrollHorizontally(-1)
+                    || mRecyclerView.canScrollHorizontally(1));
+
+            if (mRecyclerView.mAdapter != null) {
+                event.setItemCount(mRecyclerView.mAdapter.getItemCount());
+            }
+        }
+
+        // called by accessibility delegate
+        void onInitializeAccessibilityNodeInfoForItem(View host, AccessibilityNodeInfo info) {
+            final ViewHolder vh = getChildViewHolderInt(host);
+            // avoid trying to create accessibility node info for removed children
+            if (vh != null && !vh.isRemoved() && !mChildHelper.isHidden(vh.itemView)) {
+                onInitializeAccessibilityNodeInfoForItem(mRecyclerView.mRecycler,
+                        mRecyclerView.mState, host, info);
+            }
+        }
+
+        /**
+         * Called by the AccessibilityDelegate when the accessibility information for a specific
+         * item should be populated.
+         * <p>
+         * Default implementation adds basic positioning information about the item.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @param host     The child for which accessibility node info should be populated
+         * @param info     The info to fill out about the item
+         * @see android.widget.AbsListView#onInitializeAccessibilityNodeInfoForItem(View, int,
+         * android.view.accessibility.AccessibilityNodeInfo)
+         */
+        public void onInitializeAccessibilityNodeInfoForItem(Recycler recycler, State state,
+                View host, AccessibilityNodeInfo info) {
+            int rowIndexGuess = canScrollVertically() ? getPosition(host) : 0;
+            int columnIndexGuess = canScrollHorizontally() ? getPosition(host) : 0;
+            final AccessibilityNodeInfo.CollectionItemInfo itemInfo =
+                    AccessibilityNodeInfo.CollectionItemInfo.obtain(rowIndexGuess, 1,
+                            columnIndexGuess, 1, false, false);
+            info.setCollectionItemInfo(itemInfo);
+        }
+
+        /**
+         * A LayoutManager can call this method to force RecyclerView to run simple animations in
+         * the next layout pass, even if there is not any trigger to do so. (e.g. adapter data
+         * change).
+         * <p>
+         * Note that, calling this method will not guarantee that RecyclerView will run animations
+         * at all. For example, if there is not any {@link ItemAnimator} set, RecyclerView will
+         * not run any animations but will still clear this flag after the layout is complete.
+         *
+         */
+        public void requestSimpleAnimationsInNextLayout() {
+            mRequestedSimpleAnimations = true;
+        }
+
+        /**
+         * Returns the selection mode for accessibility. Should be
+         * {@link AccessibilityNodeInfo.CollectionInfo#SELECTION_MODE_NONE},
+         * {@link AccessibilityNodeInfo.CollectionInfo#SELECTION_MODE_SINGLE} or
+         * {@link AccessibilityNodeInfo.CollectionInfo#SELECTION_MODE_MULTIPLE}.
+         * <p>
+         * Default implementation returns
+         * {@link AccessibilityNodeInfo.CollectionInfo#SELECTION_MODE_NONE}.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @return Selection mode for accessibility. Default implementation returns
+         * {@link AccessibilityNodeInfo.CollectionInfo#SELECTION_MODE_NONE}.
+         */
+        public int getSelectionModeForAccessibility(Recycler recycler, State state) {
+            return AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_NONE;
+        }
+
+        /**
+         * Returns the number of rows for accessibility.
+         * <p>
+         * Default implementation returns the number of items in the adapter if LayoutManager
+         * supports vertical scrolling or 1 if LayoutManager does not support vertical
+         * scrolling.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @return The number of rows in LayoutManager for accessibility.
+         */
+        public int getRowCountForAccessibility(Recycler recycler, State state) {
+            if (mRecyclerView == null || mRecyclerView.mAdapter == null) {
+                return 1;
+            }
+            return canScrollVertically() ? mRecyclerView.mAdapter.getItemCount() : 1;
+        }
+
+        /**
+         * Returns the number of columns for accessibility.
+         * <p>
+         * Default implementation returns the number of items in the adapter if LayoutManager
+         * supports horizontal scrolling or 1 if LayoutManager does not support horizontal
+         * scrolling.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @return The number of rows in LayoutManager for accessibility.
+         */
+        public int getColumnCountForAccessibility(Recycler recycler, State state) {
+            if (mRecyclerView == null || mRecyclerView.mAdapter == null) {
+                return 1;
+            }
+            return canScrollHorizontally() ? mRecyclerView.mAdapter.getItemCount() : 1;
+        }
+
+        /**
+         * Returns whether layout is hierarchical or not to be used for accessibility.
+         * <p>
+         * Default implementation returns false.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @return True if layout is hierarchical.
+         */
+        public boolean isLayoutHierarchical(Recycler recycler, State state) {
+            return false;
+        }
+
+        // called by accessibility delegate
+        boolean performAccessibilityAction(int action, Bundle args) {
+            return performAccessibilityAction(mRecyclerView.mRecycler, mRecyclerView.mState,
+                    action, args);
+        }
+
+        /**
+         * Called by AccessibilityDelegate when an action is requested from the RecyclerView.
+         *
+         * @param recycler  The Recycler that can be used to convert view positions into adapter
+         *                  positions
+         * @param state     The current state of RecyclerView
+         * @param action    The action to perform
+         * @param args      Optional action arguments
+         * @see View#performAccessibilityAction(int, android.os.Bundle)
+         */
+        public boolean performAccessibilityAction(Recycler recycler, State state, int action,
+                Bundle args) {
+            if (mRecyclerView == null) {
+                return false;
+            }
+            int vScroll = 0, hScroll = 0;
+            switch (action) {
+                case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
+                    if (mRecyclerView.canScrollVertically(-1)) {
+                        vScroll = -(getHeight() - getPaddingTop() - getPaddingBottom());
+                    }
+                    if (mRecyclerView.canScrollHorizontally(-1)) {
+                        hScroll = -(getWidth() - getPaddingLeft() - getPaddingRight());
+                    }
+                    break;
+                case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
+                    if (mRecyclerView.canScrollVertically(1)) {
+                        vScroll = getHeight() - getPaddingTop() - getPaddingBottom();
+                    }
+                    if (mRecyclerView.canScrollHorizontally(1)) {
+                        hScroll = getWidth() - getPaddingLeft() - getPaddingRight();
+                    }
+                    break;
+            }
+            if (vScroll == 0 && hScroll == 0) {
+                return false;
+            }
+            mRecyclerView.scrollBy(hScroll, vScroll);
+            return true;
+        }
+
+        // called by accessibility delegate
+        boolean performAccessibilityActionForItem(View view, int action, Bundle args) {
+            return performAccessibilityActionForItem(mRecyclerView.mRecycler, mRecyclerView.mState,
+                    view, action, args);
+        }
+
+        /**
+         * Called by AccessibilityDelegate when an accessibility action is requested on one of the
+         * children of LayoutManager.
+         * <p>
+         * Default implementation does not do anything.
+         *
+         * @param recycler The Recycler that can be used to convert view positions into adapter
+         *                 positions
+         * @param state    The current state of RecyclerView
+         * @param view     The child view on which the action is performed
+         * @param action   The action to perform
+         * @param args     Optional action arguments
+         * @return true if action is handled
+         * @see View#performAccessibilityAction(int, android.os.Bundle)
+         */
+        public boolean performAccessibilityActionForItem(Recycler recycler, State state, View view,
+                int action, Bundle args) {
+            return false;
+        }
+
+        /**
+         * Parse the xml attributes to get the most common properties used by layout managers.
+         *
+         * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation
+         * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount
+         * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout
+         * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd
+         *
+         * @return an object containing the properties as specified in the attrs.
+         */
+        public static Properties getProperties(Context context, AttributeSet attrs,
+                int defStyleAttr, int defStyleRes) {
+            Properties properties = new Properties();
+            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecyclerView,
+                    defStyleAttr, defStyleRes);
+            properties.orientation = a.getInt(R.styleable.RecyclerView_orientation, VERTICAL);
+            properties.spanCount = a.getInt(R.styleable.RecyclerView_spanCount, 1);
+            properties.reverseLayout = a.getBoolean(R.styleable.RecyclerView_reverseLayout, false);
+            properties.stackFromEnd = a.getBoolean(R.styleable.RecyclerView_stackFromEnd, false);
+            a.recycle();
+            return properties;
+        }
+
+        void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
+            setMeasureSpecs(
+                    MeasureSpec.makeMeasureSpec(recyclerView.getWidth(), MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(recyclerView.getHeight(), MeasureSpec.EXACTLY)
+            );
+        }
+
+        /**
+         * Internal API to allow LayoutManagers to be measured twice.
+         * <p>
+         * This is not public because LayoutManagers should be able to handle their layouts in one
+         * pass but it is very convenient to make existing LayoutManagers support wrapping content
+         * when both orientations are undefined.
+         * <p>
+         * This API will be removed after default LayoutManagers properly implement wrap content in
+         * non-scroll orientation.
+         */
+        boolean shouldMeasureTwice() {
+            return false;
+        }
+
+        boolean hasFlexibleChildInBothOrientations() {
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final ViewGroup.LayoutParams lp = child.getLayoutParams();
+                if (lp.width < 0 && lp.height < 0) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Some general properties that a LayoutManager may want to use.
+         */
+        public static class Properties {
+            /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation */
+            public int orientation;
+            /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount */
+            public int spanCount;
+            /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout */
+            public boolean reverseLayout;
+            /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd */
+            public boolean stackFromEnd;
+        }
+    }
+
+    /**
+     * An ItemDecoration allows the application to add a special drawing and layout offset
+     * to specific item views from the adapter's data set. This can be useful for drawing dividers
+     * between items, highlights, visual grouping boundaries and more.
+     *
+     * <p>All ItemDecorations are drawn in the order they were added, before the item
+     * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()}
+     * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView,
+     * RecyclerView.State)}.</p>
+     */
+    public abstract static class ItemDecoration {
+        /**
+         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
+         * Any content drawn by this method will be drawn before the item views are drawn,
+         * and will thus appear underneath the views.
+         *
+         * @param c Canvas to draw into
+         * @param parent RecyclerView this ItemDecoration is drawing into
+         * @param state The current state of RecyclerView
+         */
+        public void onDraw(Canvas c, RecyclerView parent, State state) {
+            onDraw(c, parent);
+        }
+
+        /**
+         * @deprecated
+         * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
+         */
+        @Deprecated
+        public void onDraw(Canvas c, RecyclerView parent) {
+        }
+
+        /**
+         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
+         * Any content drawn by this method will be drawn after the item views are drawn
+         * and will thus appear over the views.
+         *
+         * @param c Canvas to draw into
+         * @param parent RecyclerView this ItemDecoration is drawing into
+         * @param state The current state of RecyclerView.
+         */
+        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
+            onDrawOver(c, parent);
+        }
+
+        /**
+         * @deprecated
+         * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
+         */
+        @Deprecated
+        public void onDrawOver(Canvas c, RecyclerView parent) {
+        }
+
+
+        /**
+         * @deprecated
+         * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
+         */
+        @Deprecated
+        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
+            outRect.set(0, 0, 0, 0);
+        }
+
+        /**
+         * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
+         * the number of pixels that the item view should be inset by, similar to padding or margin.
+         * The default implementation sets the bounds of outRect to 0 and returns.
+         *
+         * <p>
+         * If this ItemDecoration does not affect the positioning of item views, it should set
+         * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
+         * before returning.
+         *
+         * <p>
+         * If you need to access Adapter for additional data, you can call
+         * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
+         * View.
+         *
+         * @param outRect Rect to receive the output.
+         * @param view    The child view to decorate
+         * @param parent  RecyclerView this ItemDecoration is decorating
+         * @param state   The current state of RecyclerView.
+         */
+        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
+            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
+                    parent);
+        }
+    }
+
+    /**
+     * An OnItemTouchListener allows the application to intercept touch events in progress at the
+     * view hierarchy level of the RecyclerView before those touch events are considered for
+     * RecyclerView's own scrolling behavior.
+     *
+     * <p>This can be useful for applications that wish to implement various forms of gestural
+     * manipulation of item views within the RecyclerView. OnItemTouchListeners may intercept
+     * a touch interaction already in progress even if the RecyclerView is already handling that
+     * gesture stream itself for the purposes of scrolling.</p>
+     *
+     * @see SimpleOnItemTouchListener
+     */
+    public interface OnItemTouchListener {
+        /**
+         * Silently observe and/or take over touch events sent to the RecyclerView
+         * before they are handled by either the RecyclerView itself or its child views.
+         *
+         * <p>The onInterceptTouchEvent methods of each attached OnItemTouchListener will be run
+         * in the order in which each listener was added, before any other touch processing
+         * by the RecyclerView itself or child views occurs.</p>
+         *
+         * @param e MotionEvent describing the touch event. All coordinates are in
+         *          the RecyclerView's coordinate system.
+         * @return true if this OnItemTouchListener wishes to begin intercepting touch events, false
+         *         to continue with the current behavior and continue observing future events in
+         *         the gesture.
+         */
+        boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e);
+
+        /**
+         * Process a touch event as part of a gesture that was claimed by returning true from
+         * a previous call to {@link #onInterceptTouchEvent}.
+         *
+         * @param e MotionEvent describing the touch event. All coordinates are in
+         *          the RecyclerView's coordinate system.
+         */
+        void onTouchEvent(RecyclerView rv, MotionEvent e);
+
+        /**
+         * Called when a child of RecyclerView does not want RecyclerView and its ancestors to
+         * intercept touch events with
+         * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}.
+         *
+         * @param disallowIntercept True if the child does not want the parent to
+         *            intercept touch events.
+         * @see ViewParent#requestDisallowInterceptTouchEvent(boolean)
+         */
+        void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
+    }
+
+    /**
+     * An implementation of {@link RecyclerView.OnItemTouchListener} that has empty method bodies
+     * and default return values.
+     * <p>
+     * You may prefer to extend this class if you don't need to override all methods. Another
+     * benefit of using this class is future compatibility. As the interface may change, we'll
+     * always provide a default implementation on this class so that your code won't break when
+     * you update to a new version of the support library.
+     */
+    public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener {
+        @Override
+        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+            return false;
+        }
+
+        @Override
+        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        }
+
+        @Override
+        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        }
+    }
+
+
+    /**
+     * An OnScrollListener can be added to a RecyclerView to receive messages when a scrolling event
+     * has occurred on that RecyclerView.
+     * <p>
+     * @see RecyclerView#addOnScrollListener(OnScrollListener)
+     * @see RecyclerView#clearOnChildAttachStateChangeListeners()
+     *
+     */
+    public abstract static class OnScrollListener {
+        /**
+         * Callback method to be invoked when RecyclerView's scroll state changes.
+         *
+         * @param recyclerView The RecyclerView whose scroll state has changed.
+         * @param newState     The updated scroll state. One of {@link #SCROLL_STATE_IDLE},
+         *                     {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}.
+         */
+        public void onScrollStateChanged(RecyclerView recyclerView, int newState){}
+
+        /**
+         * Callback method to be invoked when the RecyclerView has been scrolled. This will be
+         * called after the scroll has completed.
+         * <p>
+         * This callback will also be called if visible item range changes after a layout
+         * calculation. In that case, dx and dy will be 0.
+         *
+         * @param recyclerView The RecyclerView which scrolled.
+         * @param dx The amount of horizontal scroll.
+         * @param dy The amount of vertical scroll.
+         */
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy){}
+    }
+
+    /**
+     * A RecyclerListener can be set on a RecyclerView to receive messages whenever
+     * a view is recycled.
+     *
+     * @see RecyclerView#setRecyclerListener(RecyclerListener)
+     */
+    public interface RecyclerListener {
+
+        /**
+         * This method is called whenever the view in the ViewHolder is recycled.
+         *
+         * RecyclerView calls this method right before clearing ViewHolder's internal data and
+         * sending it to RecycledViewPool. This way, if ViewHolder was holding valid information
+         * before being recycled, you can call {@link ViewHolder#getAdapterPosition()} to get
+         * its adapter position.
+         *
+         * @param holder The ViewHolder containing the view that was recycled
+         */
+        void onViewRecycled(ViewHolder holder);
+    }
+
+    /**
+     * A Listener interface that can be attached to a RecylcerView to get notified
+     * whenever a ViewHolder is attached to or detached from RecyclerView.
+     */
+    public interface OnChildAttachStateChangeListener {
+
+        /**
+         * Called when a view is attached to the RecyclerView.
+         *
+         * @param view The View which is attached to the RecyclerView
+         */
+        void onChildViewAttachedToWindow(View view);
+
+        /**
+         * Called when a view is detached from RecyclerView.
+         *
+         * @param view The View which is being detached from the RecyclerView
+         */
+        void onChildViewDetachedFromWindow(View view);
+    }
+
+    /**
+     * A ViewHolder describes an item view and metadata about its place within the RecyclerView.
+     *
+     * <p>{@link Adapter} implementations should subclass ViewHolder and add fields for caching
+     * potentially expensive {@link View#findViewById(int)} results.</p>
+     *
+     * <p>While {@link LayoutParams} belong to the {@link LayoutManager},
+     * {@link ViewHolder ViewHolders} belong to the adapter. Adapters should feel free to use
+     * their own custom ViewHolder implementations to store data that makes binding view contents
+     * easier. Implementations should assume that individual item views will hold strong references
+     * to <code>ViewHolder</code> objects and that <code>RecyclerView</code> instances may hold
+     * strong references to extra off-screen item views for caching purposes</p>
+     */
+    public abstract static class ViewHolder {
+        public final View itemView;
+        WeakReference<RecyclerView> mNestedRecyclerView;
+        int mPosition = NO_POSITION;
+        int mOldPosition = NO_POSITION;
+        long mItemId = NO_ID;
+        int mItemViewType = INVALID_TYPE;
+        int mPreLayoutPosition = NO_POSITION;
+
+        // The item that this holder is shadowing during an item change event/animation
+        ViewHolder mShadowedHolder = null;
+        // The item that is shadowing this holder during an item change event/animation
+        ViewHolder mShadowingHolder = null;
+
+        /**
+         * This ViewHolder has been bound to a position; mPosition, mItemId and mItemViewType
+         * are all valid.
+         */
+        static final int FLAG_BOUND = 1 << 0;
+
+        /**
+         * The data this ViewHolder's view reflects is stale and needs to be rebound
+         * by the adapter. mPosition and mItemId are consistent.
+         */
+        static final int FLAG_UPDATE = 1 << 1;
+
+        /**
+         * This ViewHolder's data is invalid. The identity implied by mPosition and mItemId
+         * are not to be trusted and may no longer match the item view type.
+         * This ViewHolder must be fully rebound to different data.
+         */
+        static final int FLAG_INVALID = 1 << 2;
+
+        /**
+         * This ViewHolder points at data that represents an item previously removed from the
+         * data set. Its view may still be used for things like outgoing animations.
+         */
+        static final int FLAG_REMOVED = 1 << 3;
+
+        /**
+         * This ViewHolder should not be recycled. This flag is set via setIsRecyclable()
+         * and is intended to keep views around during animations.
+         */
+        static final int FLAG_NOT_RECYCLABLE = 1 << 4;
+
+        /**
+         * This ViewHolder is returned from scrap which means we are expecting an addView call
+         * for this itemView. When returned from scrap, ViewHolder stays in the scrap list until
+         * the end of the layout pass and then recycled by RecyclerView if it is not added back to
+         * the RecyclerView.
+         */
+        static final int FLAG_RETURNED_FROM_SCRAP = 1 << 5;
+
+        /**
+         * This ViewHolder is fully managed by the LayoutManager. We do not scrap, recycle or remove
+         * it unless LayoutManager is replaced.
+         * It is still fully visible to the LayoutManager.
+         */
+        static final int FLAG_IGNORE = 1 << 7;
+
+        /**
+         * When the View is detached form the parent, we set this flag so that we can take correct
+         * action when we need to remove it or add it back.
+         */
+        static final int FLAG_TMP_DETACHED = 1 << 8;
+
+        /**
+         * Set when we can no longer determine the adapter position of this ViewHolder until it is
+         * rebound to a new position. It is different than FLAG_INVALID because FLAG_INVALID is
+         * set even when the type does not match. Also, FLAG_ADAPTER_POSITION_UNKNOWN is set as soon
+         * as adapter notification arrives vs FLAG_INVALID is set lazily before layout is
+         * re-calculated.
+         */
+        static final int FLAG_ADAPTER_POSITION_UNKNOWN = 1 << 9;
+
+        /**
+         * Set when a addChangePayload(null) is called
+         */
+        static final int FLAG_ADAPTER_FULLUPDATE = 1 << 10;
+
+        /**
+         * Used by ItemAnimator when a ViewHolder's position changes
+         */
+        static final int FLAG_MOVED = 1 << 11;
+
+        /**
+         * Used by ItemAnimator when a ViewHolder appears in pre-layout
+         */
+        static final int FLAG_APPEARED_IN_PRE_LAYOUT = 1 << 12;
+
+        static final int PENDING_ACCESSIBILITY_STATE_NOT_SET = -1;
+
+        /**
+         * Used when a ViewHolder starts the layout pass as a hidden ViewHolder but is re-used from
+         * hidden list (as if it was scrap) without being recycled in between.
+         *
+         * When a ViewHolder is hidden, there are 2 paths it can be re-used:
+         *   a) Animation ends, view is recycled and used from the recycle pool.
+         *   b) LayoutManager asks for the View for that position while the ViewHolder is hidden.
+         *
+         * This flag is used to represent "case b" where the ViewHolder is reused without being
+         * recycled (thus "bounced" from the hidden list). This state requires special handling
+         * because the ViewHolder must be added to pre layout maps for animations as if it was
+         * already there.
+         */
+        static final int FLAG_BOUNCED_FROM_HIDDEN_LIST = 1 << 13;
+
+        private int mFlags;
+
+        private static final List<Object> FULLUPDATE_PAYLOADS = Collections.EMPTY_LIST;
+
+        List<Object> mPayloads = null;
+        List<Object> mUnmodifiedPayloads = null;
+
+        private int mIsRecyclableCount = 0;
+
+        // If non-null, view is currently considered scrap and may be reused for other data by the
+        // scrap container.
+        private Recycler mScrapContainer = null;
+        // Keeps whether this ViewHolder lives in Change scrap or Attached scrap
+        private boolean mInChangeScrap = false;
+
+        // Saves isImportantForAccessibility value for the view item while it's in hidden state and
+        // marked as unimportant for accessibility.
+        private int mWasImportantForAccessibilityBeforeHidden =
+                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+        // set if we defer the accessibility state change of the view holder
+        @VisibleForTesting
+        int mPendingAccessibilityState = PENDING_ACCESSIBILITY_STATE_NOT_SET;
+
+        /**
+         * Is set when VH is bound from the adapter and cleaned right before it is sent to
+         * {@link RecycledViewPool}.
+         */
+        RecyclerView mOwnerRecyclerView;
+
+        public ViewHolder(View itemView) {
+            if (itemView == null) {
+                throw new IllegalArgumentException("itemView may not be null");
+            }
+            this.itemView = itemView;
+        }
+
+        void flagRemovedAndOffsetPosition(int mNewPosition, int offset, boolean applyToPreLayout) {
+            addFlags(ViewHolder.FLAG_REMOVED);
+            offsetPosition(offset, applyToPreLayout);
+            mPosition = mNewPosition;
+        }
+
+        void offsetPosition(int offset, boolean applyToPreLayout) {
+            if (mOldPosition == NO_POSITION) {
+                mOldPosition = mPosition;
+            }
+            if (mPreLayoutPosition == NO_POSITION) {
+                mPreLayoutPosition = mPosition;
+            }
+            if (applyToPreLayout) {
+                mPreLayoutPosition += offset;
+            }
+            mPosition += offset;
+            if (itemView.getLayoutParams() != null) {
+                ((LayoutParams) itemView.getLayoutParams()).mInsetsDirty = true;
+            }
+        }
+
+        void clearOldPosition() {
+            mOldPosition = NO_POSITION;
+            mPreLayoutPosition = NO_POSITION;
+        }
+
+        void saveOldPosition() {
+            if (mOldPosition == NO_POSITION) {
+                mOldPosition = mPosition;
+            }
+        }
+
+        boolean shouldIgnore() {
+            return (mFlags & FLAG_IGNORE) != 0;
+        }
+
+        /**
+         * @deprecated This method is deprecated because its meaning is ambiguous due to the async
+         * handling of adapter updates. Please use {@link #getLayoutPosition()} or
+         * {@link #getAdapterPosition()} depending on your use case.
+         *
+         * @see #getLayoutPosition()
+         * @see #getAdapterPosition()
+         */
+        @Deprecated
+        public final int getPosition() {
+            return mPreLayoutPosition == NO_POSITION ? mPosition : mPreLayoutPosition;
+        }
+
+        /**
+         * Returns the position of the ViewHolder in terms of the latest layout pass.
+         * <p>
+         * This position is mostly used by RecyclerView components to be consistent while
+         * RecyclerView lazily processes adapter updates.
+         * <p>
+         * For performance and animation reasons, RecyclerView batches all adapter updates until the
+         * next layout pass. This may cause mismatches between the Adapter position of the item and
+         * the position it had in the latest layout calculations.
+         * <p>
+         * LayoutManagers should always call this method while doing calculations based on item
+         * positions. All methods in {@link RecyclerView.LayoutManager}, {@link RecyclerView.State},
+         * {@link RecyclerView.Recycler} that receive a position expect it to be the layout position
+         * of the item.
+         * <p>
+         * If LayoutManager needs to call an external method that requires the adapter position of
+         * the item, it can use {@link #getAdapterPosition()} or
+         * {@link RecyclerView.Recycler#convertPreLayoutPositionToPostLayout(int)}.
+         *
+         * @return Returns the adapter position of the ViewHolder in the latest layout pass.
+         * @see #getAdapterPosition()
+         */
+        public final int getLayoutPosition() {
+            return mPreLayoutPosition == NO_POSITION ? mPosition : mPreLayoutPosition;
+        }
+
+        /**
+         * Returns the Adapter position of the item represented by this ViewHolder.
+         * <p>
+         * Note that this might be different than the {@link #getLayoutPosition()} if there are
+         * pending adapter updates but a new layout pass has not happened yet.
+         * <p>
+         * RecyclerView does not handle any adapter updates until the next layout traversal. This
+         * may create temporary inconsistencies between what user sees on the screen and what
+         * adapter contents have. This inconsistency is not important since it will be less than
+         * 16ms but it might be a problem if you want to use ViewHolder position to access the
+         * adapter. Sometimes, you may need to get the exact adapter position to do
+         * some actions in response to user events. In that case, you should use this method which
+         * will calculate the Adapter position of the ViewHolder.
+         * <p>
+         * Note that if you've called {@link RecyclerView.Adapter#notifyDataSetChanged()}, until the
+         * next layout pass, the return value of this method will be {@link #NO_POSITION}.
+         *
+         * @return The adapter position of the item if it still exists in the adapter.
+         * {@link RecyclerView#NO_POSITION} if item has been removed from the adapter,
+         * {@link RecyclerView.Adapter#notifyDataSetChanged()} has been called after the last
+         * layout pass or the ViewHolder has already been recycled.
+         */
+        public final int getAdapterPosition() {
+            if (mOwnerRecyclerView == null) {
+                return NO_POSITION;
+            }
+            return mOwnerRecyclerView.getAdapterPositionFor(this);
+        }
+
+        /**
+         * When LayoutManager supports animations, RecyclerView tracks 3 positions for ViewHolders
+         * to perform animations.
+         * <p>
+         * If a ViewHolder was laid out in the previous onLayout call, old position will keep its
+         * adapter index in the previous layout.
+         *
+         * @return The previous adapter index of the Item represented by this ViewHolder or
+         * {@link #NO_POSITION} if old position does not exists or cleared (pre-layout is
+         * complete).
+         */
+        public final int getOldPosition() {
+            return mOldPosition;
+        }
+
+        /**
+         * Returns The itemId represented by this ViewHolder.
+         *
+         * @return The item's id if adapter has stable ids, {@link RecyclerView#NO_ID}
+         * otherwise
+         */
+        public final long getItemId() {
+            return mItemId;
+        }
+
+        /**
+         * @return The view type of this ViewHolder.
+         */
+        public final int getItemViewType() {
+            return mItemViewType;
+        }
+
+        boolean isScrap() {
+            return mScrapContainer != null;
+        }
+
+        void unScrap() {
+            mScrapContainer.unscrapView(this);
+        }
+
+        boolean wasReturnedFromScrap() {
+            return (mFlags & FLAG_RETURNED_FROM_SCRAP) != 0;
+        }
+
+        void clearReturnedFromScrapFlag() {
+            mFlags = mFlags & ~FLAG_RETURNED_FROM_SCRAP;
+        }
+
+        void clearTmpDetachFlag() {
+            mFlags = mFlags & ~FLAG_TMP_DETACHED;
+        }
+
+        void stopIgnoring() {
+            mFlags = mFlags & ~FLAG_IGNORE;
+        }
+
+        void setScrapContainer(Recycler recycler, boolean isChangeScrap) {
+            mScrapContainer = recycler;
+            mInChangeScrap = isChangeScrap;
+        }
+
+        boolean isInvalid() {
+            return (mFlags & FLAG_INVALID) != 0;
+        }
+
+        boolean needsUpdate() {
+            return (mFlags & FLAG_UPDATE) != 0;
+        }
+
+        boolean isBound() {
+            return (mFlags & FLAG_BOUND) != 0;
+        }
+
+        boolean isRemoved() {
+            return (mFlags & FLAG_REMOVED) != 0;
+        }
+
+        boolean hasAnyOfTheFlags(int flags) {
+            return (mFlags & flags) != 0;
+        }
+
+        boolean isTmpDetached() {
+            return (mFlags & FLAG_TMP_DETACHED) != 0;
+        }
+
+        boolean isAdapterPositionUnknown() {
+            return (mFlags & FLAG_ADAPTER_POSITION_UNKNOWN) != 0 || isInvalid();
+        }
+
+        void setFlags(int flags, int mask) {
+            mFlags = (mFlags & ~mask) | (flags & mask);
+        }
+
+        void addFlags(int flags) {
+            mFlags |= flags;
+        }
+
+        void addChangePayload(Object payload) {
+            if (payload == null) {
+                addFlags(FLAG_ADAPTER_FULLUPDATE);
+            } else if ((mFlags & FLAG_ADAPTER_FULLUPDATE) == 0) {
+                createPayloadsIfNeeded();
+                mPayloads.add(payload);
+            }
+        }
+
+        private void createPayloadsIfNeeded() {
+            if (mPayloads == null) {
+                mPayloads = new ArrayList<Object>();
+                mUnmodifiedPayloads = Collections.unmodifiableList(mPayloads);
+            }
+        }
+
+        void clearPayload() {
+            if (mPayloads != null) {
+                mPayloads.clear();
+            }
+            mFlags = mFlags & ~FLAG_ADAPTER_FULLUPDATE;
+        }
+
+        List<Object> getUnmodifiedPayloads() {
+            if ((mFlags & FLAG_ADAPTER_FULLUPDATE) == 0) {
+                if (mPayloads == null || mPayloads.size() == 0) {
+                    // Initial state,  no update being called.
+                    return FULLUPDATE_PAYLOADS;
+                }
+                // there are none-null payloads
+                return mUnmodifiedPayloads;
+            } else {
+                // a full update has been called.
+                return FULLUPDATE_PAYLOADS;
+            }
+        }
+
+        void resetInternal() {
+            mFlags = 0;
+            mPosition = NO_POSITION;
+            mOldPosition = NO_POSITION;
+            mItemId = NO_ID;
+            mPreLayoutPosition = NO_POSITION;
+            mIsRecyclableCount = 0;
+            mShadowedHolder = null;
+            mShadowingHolder = null;
+            clearPayload();
+            mWasImportantForAccessibilityBeforeHidden = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+            mPendingAccessibilityState = PENDING_ACCESSIBILITY_STATE_NOT_SET;
+            clearNestedRecyclerViewIfNotNested(this);
+        }
+
+        /**
+         * Called when the child view enters the hidden state
+         */
+        private void onEnteredHiddenState(RecyclerView parent) {
+            // While the view item is in hidden state, make it invisible for the accessibility.
+            mWasImportantForAccessibilityBeforeHidden =
+                    itemView.getImportantForAccessibility();
+            parent.setChildImportantForAccessibilityInternal(this,
+                    View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+        }
+
+        /**
+         * Called when the child view leaves the hidden state
+         */
+        private void onLeftHiddenState(RecyclerView parent) {
+            parent.setChildImportantForAccessibilityInternal(this,
+                    mWasImportantForAccessibilityBeforeHidden);
+            mWasImportantForAccessibilityBeforeHidden = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("ViewHolder{"
+                    + Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId
+                    + ", oldPos=" + mOldPosition + ", pLpos:" + mPreLayoutPosition);
+            if (isScrap()) {
+                sb.append(" scrap ")
+                        .append(mInChangeScrap ? "[changeScrap]" : "[attachedScrap]");
+            }
+            if (isInvalid()) sb.append(" invalid");
+            if (!isBound()) sb.append(" unbound");
+            if (needsUpdate()) sb.append(" update");
+            if (isRemoved()) sb.append(" removed");
+            if (shouldIgnore()) sb.append(" ignored");
+            if (isTmpDetached()) sb.append(" tmpDetached");
+            if (!isRecyclable()) sb.append(" not recyclable(" + mIsRecyclableCount + ")");
+            if (isAdapterPositionUnknown()) sb.append(" undefined adapter position");
+
+            if (itemView.getParent() == null) sb.append(" no parent");
+            sb.append("}");
+            return sb.toString();
+        }
+
+        /**
+         * Informs the recycler whether this item can be recycled. Views which are not
+         * recyclable will not be reused for other items until setIsRecyclable() is
+         * later set to true. Calls to setIsRecyclable() should always be paired (one
+         * call to setIsRecyclabe(false) should always be matched with a later call to
+         * setIsRecyclable(true)). Pairs of calls may be nested, as the state is internally
+         * reference-counted.
+         *
+         * @param recyclable Whether this item is available to be recycled. Default value
+         * is true.
+         *
+         * @see #isRecyclable()
+         */
+        public final void setIsRecyclable(boolean recyclable) {
+            mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 : mIsRecyclableCount + 1;
+            if (mIsRecyclableCount < 0) {
+                mIsRecyclableCount = 0;
+                if (DEBUG) {
+                    throw new RuntimeException("isRecyclable decremented below 0: "
+                            + "unmatched pair of setIsRecyable() calls for " + this);
+                }
+                Log.e(VIEW_LOG_TAG, "isRecyclable decremented below 0: "
+                        + "unmatched pair of setIsRecyable() calls for " + this);
+            } else if (!recyclable && mIsRecyclableCount == 1) {
+                mFlags |= FLAG_NOT_RECYCLABLE;
+            } else if (recyclable && mIsRecyclableCount == 0) {
+                mFlags &= ~FLAG_NOT_RECYCLABLE;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "setIsRecyclable val:" + recyclable + ":" + this);
+            }
+        }
+
+        /**
+         * @return true if this item is available to be recycled, false otherwise.
+         *
+         * @see #setIsRecyclable(boolean)
+         */
+        public final boolean isRecyclable() {
+            return (mFlags & FLAG_NOT_RECYCLABLE) == 0
+                    && !itemView.hasTransientState();
+        }
+
+        /**
+         * Returns whether we have animations referring to this view holder or not.
+         * This is similar to isRecyclable flag but does not check transient state.
+         */
+        private boolean shouldBeKeptAsChild() {
+            return (mFlags & FLAG_NOT_RECYCLABLE) != 0;
+        }
+
+        /**
+         * @return True if ViewHolder is not referenced by RecyclerView animations but has
+         * transient state which will prevent it from being recycled.
+         */
+        private boolean doesTransientStatePreventRecycling() {
+            return (mFlags & FLAG_NOT_RECYCLABLE) == 0 && itemView.hasTransientState();
+        }
+
+        boolean isUpdated() {
+            return (mFlags & FLAG_UPDATE) != 0;
+        }
+    }
+
+    /**
+     * This method is here so that we can control the important for a11y changes and test it.
+     */
+    @VisibleForTesting
+    boolean setChildImportantForAccessibilityInternal(ViewHolder viewHolder,
+            int importantForAccessibility) {
+        if (isComputingLayout()) {
+            viewHolder.mPendingAccessibilityState = importantForAccessibility;
+            mPendingAccessibilityImportanceChange.add(viewHolder);
+            return false;
+        }
+        viewHolder.itemView.setImportantForAccessibility(importantForAccessibility);
+        return true;
+    }
+
+    void dispatchPendingImportantForAccessibilityChanges() {
+        for (int i = mPendingAccessibilityImportanceChange.size() - 1; i >= 0; i--) {
+            ViewHolder viewHolder = mPendingAccessibilityImportanceChange.get(i);
+            if (viewHolder.itemView.getParent() != this || viewHolder.shouldIgnore()) {
+                continue;
+            }
+            int state = viewHolder.mPendingAccessibilityState;
+            if (state != ViewHolder.PENDING_ACCESSIBILITY_STATE_NOT_SET) {
+                //noinspection WrongConstant
+                viewHolder.itemView.setImportantForAccessibility(state);
+                viewHolder.mPendingAccessibilityState =
+                        ViewHolder.PENDING_ACCESSIBILITY_STATE_NOT_SET;
+            }
+        }
+        mPendingAccessibilityImportanceChange.clear();
+    }
+
+    int getAdapterPositionFor(ViewHolder viewHolder) {
+        if (viewHolder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
+                | ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)
+                || !viewHolder.isBound()) {
+            return RecyclerView.NO_POSITION;
+        }
+        return mAdapterHelper.applyPendingUpdatesToPosition(viewHolder.mPosition);
+    }
+
+    /**
+     * {@link android.view.ViewGroup.MarginLayoutParams LayoutParams} subclass for children of
+     * {@link RecyclerView}. Custom {@link LayoutManager layout managers} are encouraged
+     * to create their own subclass of this <code>LayoutParams</code> class
+     * to store any additional required per-child view metadata about the layout.
+     */
+    public static class LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+        ViewHolder mViewHolder;
+        final Rect mDecorInsets = new Rect();
+        boolean mInsetsDirty = true;
+        // Flag is set to true if the view is bound while it is detached from RV.
+        // In this case, we need to manually call invalidate after view is added to guarantee that
+        // invalidation is populated through the View hierarchy
+        boolean mPendingInvalidate = false;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super((ViewGroup.LayoutParams) source);
+        }
+
+        /**
+         * Returns true if the view this LayoutParams is attached to needs to have its content
+         * updated from the corresponding adapter.
+         *
+         * @return true if the view should have its content updated
+         */
+        public boolean viewNeedsUpdate() {
+            return mViewHolder.needsUpdate();
+        }
+
+        /**
+         * Returns true if the view this LayoutParams is attached to is now representing
+         * potentially invalid data. A LayoutManager should scrap/recycle it.
+         *
+         * @return true if the view is invalid
+         */
+        public boolean isViewInvalid() {
+            return mViewHolder.isInvalid();
+        }
+
+        /**
+         * Returns true if the adapter data item corresponding to the view this LayoutParams
+         * is attached to has been removed from the data set. A LayoutManager may choose to
+         * treat it differently in order to animate its outgoing or disappearing state.
+         *
+         * @return true if the item the view corresponds to was removed from the data set
+         */
+        public boolean isItemRemoved() {
+            return mViewHolder.isRemoved();
+        }
+
+        /**
+         * Returns true if the adapter data item corresponding to the view this LayoutParams
+         * is attached to has been changed in the data set. A LayoutManager may choose to
+         * treat it differently in order to animate its changing state.
+         *
+         * @return true if the item the view corresponds to was changed in the data set
+         */
+        public boolean isItemChanged() {
+            return mViewHolder.isUpdated();
+        }
+
+        /**
+         * @deprecated use {@link #getViewLayoutPosition()} or {@link #getViewAdapterPosition()}
+         */
+        @Deprecated
+        public int getViewPosition() {
+            return mViewHolder.getPosition();
+        }
+
+        /**
+         * Returns the adapter position that the view this LayoutParams is attached to corresponds
+         * to as of latest layout calculation.
+         *
+         * @return the adapter position this view as of latest layout pass
+         */
+        public int getViewLayoutPosition() {
+            return mViewHolder.getLayoutPosition();
+        }
+
+        /**
+         * Returns the up-to-date adapter position that the view this LayoutParams is attached to
+         * corresponds to.
+         *
+         * @return the up-to-date adapter position this view. It may return
+         * {@link RecyclerView#NO_POSITION} if item represented by this View has been removed or
+         * its up-to-date position cannot be calculated.
+         */
+        public int getViewAdapterPosition() {
+            return mViewHolder.getAdapterPosition();
+        }
+    }
+
+    /**
+     * Observer base class for watching changes to an {@link Adapter}.
+     * See {@link Adapter#registerAdapterDataObserver(AdapterDataObserver)}.
+     */
+    public abstract static class AdapterDataObserver {
+        public void onChanged() {
+            // Do nothing
+        }
+
+        public void onItemRangeChanged(int positionStart, int itemCount) {
+            // do nothing
+        }
+
+        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+            // fallback to onItemRangeChanged(positionStart, itemCount) if app
+            // does not override this method.
+            onItemRangeChanged(positionStart, itemCount);
+        }
+
+        public void onItemRangeInserted(int positionStart, int itemCount) {
+            // do nothing
+        }
+
+        public void onItemRangeRemoved(int positionStart, int itemCount) {
+            // do nothing
+        }
+
+        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+            // do nothing
+        }
+    }
+
+    /**
+     * <p>Base class for smooth scrolling. Handles basic tracking of the target view position and
+     * provides methods to trigger a programmatic scroll.</p>
+     *
+     * @see LinearSmoothScroller
+     */
+    public abstract static class SmoothScroller {
+
+        private int mTargetPosition = RecyclerView.NO_POSITION;
+
+        private RecyclerView mRecyclerView;
+
+        private LayoutManager mLayoutManager;
+
+        private boolean mPendingInitialRun;
+
+        private boolean mRunning;
+
+        private View mTargetView;
+
+        private final Action mRecyclingAction;
+
+        public SmoothScroller() {
+            mRecyclingAction = new Action(0, 0);
+        }
+
+        /**
+         * Starts a smooth scroll for the given target position.
+         * <p>In each animation step, {@link RecyclerView} will check
+         * for the target view and call either
+         * {@link #onTargetFound(android.view.View, RecyclerView.State, SmoothScroller.Action)} or
+         * {@link #onSeekTargetStep(int, int, RecyclerView.State, SmoothScroller.Action)} until
+         * SmoothScroller is stopped.</p>
+         *
+         * <p>Note that if RecyclerView finds the target view, it will automatically stop the
+         * SmoothScroller. This <b>does not</b> mean that scroll will stop, it only means it will
+         * stop calling SmoothScroller in each animation step.</p>
+         */
+        void start(RecyclerView recyclerView, LayoutManager layoutManager) {
+            mRecyclerView = recyclerView;
+            mLayoutManager = layoutManager;
+            if (mTargetPosition == RecyclerView.NO_POSITION) {
+                throw new IllegalArgumentException("Invalid target position");
+            }
+            mRecyclerView.mState.mTargetPosition = mTargetPosition;
+            mRunning = true;
+            mPendingInitialRun = true;
+            mTargetView = findViewByPosition(getTargetPosition());
+            onStart();
+            mRecyclerView.mViewFlinger.postOnAnimation();
+        }
+
+        public void setTargetPosition(int targetPosition) {
+            mTargetPosition = targetPosition;
+        }
+
+        /**
+         * @return The LayoutManager to which this SmoothScroller is attached. Will return
+         * <code>null</code> after the SmoothScroller is stopped.
+         */
+        @Nullable
+        public LayoutManager getLayoutManager() {
+            return mLayoutManager;
+        }
+
+        /**
+         * Stops running the SmoothScroller in each animation callback. Note that this does not
+         * cancel any existing {@link Action} updated by
+         * {@link #onTargetFound(android.view.View, RecyclerView.State, SmoothScroller.Action)} or
+         * {@link #onSeekTargetStep(int, int, RecyclerView.State, SmoothScroller.Action)}.
+         */
+        protected final void stop() {
+            if (!mRunning) {
+                return;
+            }
+            onStop();
+            mRecyclerView.mState.mTargetPosition = RecyclerView.NO_POSITION;
+            mTargetView = null;
+            mTargetPosition = RecyclerView.NO_POSITION;
+            mPendingInitialRun = false;
+            mRunning = false;
+            // trigger a cleanup
+            mLayoutManager.onSmoothScrollerStopped(this);
+            // clear references to avoid any potential leak by a custom smooth scroller
+            mLayoutManager = null;
+            mRecyclerView = null;
+        }
+
+        /**
+         * Returns true if SmoothScroller has been started but has not received the first
+         * animation
+         * callback yet.
+         *
+         * @return True if this SmoothScroller is waiting to start
+         */
+        public boolean isPendingInitialRun() {
+            return mPendingInitialRun;
+        }
+
+
+        /**
+         * @return True if SmoothScroller is currently active
+         */
+        public boolean isRunning() {
+            return mRunning;
+        }
+
+        /**
+         * Returns the adapter position of the target item
+         *
+         * @return Adapter position of the target item or
+         * {@link RecyclerView#NO_POSITION} if no target view is set.
+         */
+        public int getTargetPosition() {
+            return mTargetPosition;
+        }
+
+        private void onAnimation(int dx, int dy) {
+            final RecyclerView recyclerView = mRecyclerView;
+            if (!mRunning || mTargetPosition == RecyclerView.NO_POSITION || recyclerView == null) {
+                stop();
+            }
+            mPendingInitialRun = false;
+            if (mTargetView != null) {
+                // verify target position
+                if (getChildPosition(mTargetView) == mTargetPosition) {
+                    onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);
+                    mRecyclingAction.runIfNecessary(recyclerView);
+                    stop();
+                } else {
+                    Log.e(TAG, "Passed over target position while smooth scrolling.");
+                    mTargetView = null;
+                }
+            }
+            if (mRunning) {
+                onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction);
+                boolean hadJumpTarget = mRecyclingAction.hasJumpTarget();
+                mRecyclingAction.runIfNecessary(recyclerView);
+                if (hadJumpTarget) {
+                    // It is not stopped so needs to be restarted
+                    if (mRunning) {
+                        mPendingInitialRun = true;
+                        recyclerView.mViewFlinger.postOnAnimation();
+                    } else {
+                        stop(); // done
+                    }
+                }
+            }
+        }
+
+        /**
+         * @see RecyclerView#getChildLayoutPosition(android.view.View)
+         */
+        public int getChildPosition(View view) {
+            return mRecyclerView.getChildLayoutPosition(view);
+        }
+
+        /**
+         * @see RecyclerView.LayoutManager#getChildCount()
+         */
+        public int getChildCount() {
+            return mRecyclerView.mLayout.getChildCount();
+        }
+
+        /**
+         * @see RecyclerView.LayoutManager#findViewByPosition(int)
+         */
+        public View findViewByPosition(int position) {
+            return mRecyclerView.mLayout.findViewByPosition(position);
+        }
+
+        /**
+         * @see RecyclerView#scrollToPosition(int)
+         * @deprecated Use {@link Action#jumpTo(int)}.
+         */
+        @Deprecated
+        public void instantScrollToPosition(int position) {
+            mRecyclerView.scrollToPosition(position);
+        }
+
+        protected void onChildAttachedToWindow(View child) {
+            if (getChildPosition(child) == getTargetPosition()) {
+                mTargetView = child;
+                if (DEBUG) {
+                    Log.d(TAG, "smooth scroll target view has been attached");
+                }
+            }
+        }
+
+        /**
+         * Normalizes the vector.
+         * @param scrollVector The vector that points to the target scroll position
+         */
+        protected void normalize(PointF scrollVector) {
+            final double magnitude = Math.sqrt(scrollVector.x * scrollVector.x + scrollVector.y
+                    * scrollVector.y);
+            scrollVector.x /= magnitude;
+            scrollVector.y /= magnitude;
+        }
+
+        /**
+         * Called when smooth scroll is started. This might be a good time to do setup.
+         */
+        protected abstract void onStart();
+
+        /**
+         * Called when smooth scroller is stopped. This is a good place to cleanup your state etc.
+         * @see #stop()
+         */
+        protected abstract void onStop();
+
+        /**
+         * <p>RecyclerView will call this method each time it scrolls until it can find the target
+         * position in the layout.</p>
+         * <p>SmoothScroller should check dx, dy and if scroll should be changed, update the
+         * provided {@link Action} to define the next scroll.</p>
+         *
+         * @param dx        Last scroll amount horizontally
+         * @param dy        Last scroll amount vertically
+         * @param state     Transient state of RecyclerView
+         * @param action    If you want to trigger a new smooth scroll and cancel the previous one,
+         *                  update this object.
+         */
+        protected abstract void onSeekTargetStep(int dx, int dy, State state, Action action);
+
+        /**
+         * Called when the target position is laid out. This is the last callback SmoothScroller
+         * will receive and it should update the provided {@link Action} to define the scroll
+         * details towards the target view.
+         * @param targetView    The view element which render the target position.
+         * @param state         Transient state of RecyclerView
+         * @param action        Action instance that you should update to define final scroll action
+         *                      towards the targetView
+         */
+        protected abstract void onTargetFound(View targetView, State state, Action action);
+
+        /**
+         * Holds information about a smooth scroll request by a {@link SmoothScroller}.
+         */
+        public static class Action {
+
+            public static final int UNDEFINED_DURATION = Integer.MIN_VALUE;
+
+            private int mDx;
+
+            private int mDy;
+
+            private int mDuration;
+
+            private int mJumpToPosition = NO_POSITION;
+
+            private Interpolator mInterpolator;
+
+            private boolean mChanged = false;
+
+            // we track this variable to inform custom implementer if they are updating the action
+            // in every animation callback
+            private int mConsecutiveUpdates = 0;
+
+            /**
+             * @param dx Pixels to scroll horizontally
+             * @param dy Pixels to scroll vertically
+             */
+            public Action(int dx, int dy) {
+                this(dx, dy, UNDEFINED_DURATION, null);
+            }
+
+            /**
+             * @param dx       Pixels to scroll horizontally
+             * @param dy       Pixels to scroll vertically
+             * @param duration Duration of the animation in milliseconds
+             */
+            public Action(int dx, int dy, int duration) {
+                this(dx, dy, duration, null);
+            }
+
+            /**
+             * @param dx           Pixels to scroll horizontally
+             * @param dy           Pixels to scroll vertically
+             * @param duration     Duration of the animation in milliseconds
+             * @param interpolator Interpolator to be used when calculating scroll position in each
+             *                     animation step
+             */
+            public Action(int dx, int dy, int duration, Interpolator interpolator) {
+                mDx = dx;
+                mDy = dy;
+                mDuration = duration;
+                mInterpolator = interpolator;
+            }
+
+            /**
+             * Instead of specifying pixels to scroll, use the target position to jump using
+             * {@link RecyclerView#scrollToPosition(int)}.
+             * <p>
+             * You may prefer using this method if scroll target is really far away and you prefer
+             * to jump to a location and smooth scroll afterwards.
+             * <p>
+             * Note that calling this method takes priority over other update methods such as
+             * {@link #update(int, int, int, Interpolator)}, {@link #setX(float)},
+             * {@link #setY(float)} and #{@link #setInterpolator(Interpolator)}. If you call
+             * {@link #jumpTo(int)}, the other changes will not be considered for this animation
+             * frame.
+             *
+             * @param targetPosition The target item position to scroll to using instant scrolling.
+             */
+            public void jumpTo(int targetPosition) {
+                mJumpToPosition = targetPosition;
+            }
+
+            boolean hasJumpTarget() {
+                return mJumpToPosition >= 0;
+            }
+
+            void runIfNecessary(RecyclerView recyclerView) {
+                if (mJumpToPosition >= 0) {
+                    final int position = mJumpToPosition;
+                    mJumpToPosition = NO_POSITION;
+                    recyclerView.jumpToPositionForSmoothScroller(position);
+                    mChanged = false;
+                    return;
+                }
+                if (mChanged) {
+                    validate();
+                    if (mInterpolator == null) {
+                        if (mDuration == UNDEFINED_DURATION) {
+                            recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy);
+                        } else {
+                            recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration);
+                        }
+                    } else {
+                        recyclerView.mViewFlinger.smoothScrollBy(
+                                mDx, mDy, mDuration, mInterpolator);
+                    }
+                    mConsecutiveUpdates++;
+                    if (mConsecutiveUpdates > 10) {
+                        // A new action is being set in every animation step. This looks like a bad
+                        // implementation. Inform developer.
+                        Log.e(TAG, "Smooth Scroll action is being updated too frequently. Make sure"
+                                + " you are not changing it unless necessary");
+                    }
+                    mChanged = false;
+                } else {
+                    mConsecutiveUpdates = 0;
+                }
+            }
+
+            private void validate() {
+                if (mInterpolator != null && mDuration < 1) {
+                    throw new IllegalStateException("If you provide an interpolator, you must"
+                            + " set a positive duration");
+                } else if (mDuration < 1) {
+                    throw new IllegalStateException("Scroll duration must be a positive number");
+                }
+            }
+
+            public int getDx() {
+                return mDx;
+            }
+
+            public void setDx(int dx) {
+                mChanged = true;
+                mDx = dx;
+            }
+
+            public int getDy() {
+                return mDy;
+            }
+
+            public void setDy(int dy) {
+                mChanged = true;
+                mDy = dy;
+            }
+
+            public int getDuration() {
+                return mDuration;
+            }
+
+            public void setDuration(int duration) {
+                mChanged = true;
+                mDuration = duration;
+            }
+
+            public Interpolator getInterpolator() {
+                return mInterpolator;
+            }
+
+            /**
+             * Sets the interpolator to calculate scroll steps
+             * @param interpolator The interpolator to use. If you specify an interpolator, you must
+             *                     also set the duration.
+             * @see #setDuration(int)
+             */
+            public void setInterpolator(Interpolator interpolator) {
+                mChanged = true;
+                mInterpolator = interpolator;
+            }
+
+            /**
+             * Updates the action with given parameters.
+             * @param dx Pixels to scroll horizontally
+             * @param dy Pixels to scroll vertically
+             * @param duration Duration of the animation in milliseconds
+             * @param interpolator Interpolator to be used when calculating scroll position in each
+             *                     animation step
+             */
+            public void update(int dx, int dy, int duration, Interpolator interpolator) {
+                mDx = dx;
+                mDy = dy;
+                mDuration = duration;
+                mInterpolator = interpolator;
+                mChanged = true;
+            }
+        }
+
+        /**
+         * An interface which is optionally implemented by custom {@link RecyclerView.LayoutManager}
+         * to provide a hint to a {@link SmoothScroller} about the location of the target position.
+         */
+        public interface ScrollVectorProvider {
+            /**
+             * Should calculate the vector that points to the direction where the target position
+             * can be found.
+             * <p>
+             * This method is used by the {@link LinearSmoothScroller} to initiate a scroll towards
+             * the target position.
+             * <p>
+             * The magnitude of the vector is not important. It is always normalized before being
+             * used by the {@link LinearSmoothScroller}.
+             * <p>
+             * LayoutManager should not check whether the position exists in the adapter or not.
+             *
+             * @param targetPosition the target position to which the returned vector should point
+             *
+             * @return the scroll vector for a given position.
+             */
+            PointF computeScrollVectorForPosition(int targetPosition);
+        }
+    }
+
+    static class AdapterDataObservable extends Observable<AdapterDataObserver> {
+        public boolean hasObservers() {
+            return !mObservers.isEmpty();
+        }
+
+        public void notifyChanged() {
+            // since onChanged() is implemented by the app, it could do anything, including
+            // removing itself from {@link mObservers} - and that could cause problems if
+            // an iterator is used on the ArrayList {@link mObservers}.
+            // to avoid such problems, just march thru the list in the reverse order.
+            for (int i = mObservers.size() - 1; i >= 0; i--) {
+                mObservers.get(i).onChanged();
+            }
+        }
+
+        public void notifyItemRangeChanged(int positionStart, int itemCount) {
+            notifyItemRangeChanged(positionStart, itemCount, null);
+        }
+
+        public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) {
+            // since onItemRangeChanged() is implemented by the app, it could do anything, including
+            // removing itself from {@link mObservers} - and that could cause problems if
+            // an iterator is used on the ArrayList {@link mObservers}.
+            // to avoid such problems, just march thru the list in the reverse order.
+            for (int i = mObservers.size() - 1; i >= 0; i--) {
+                mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
+            }
+        }
+
+        public void notifyItemRangeInserted(int positionStart, int itemCount) {
+            // since onItemRangeInserted() is implemented by the app, it could do anything,
+            // including removing itself from {@link mObservers} - and that could cause problems if
+            // an iterator is used on the ArrayList {@link mObservers}.
+            // to avoid such problems, just march thru the list in the reverse order.
+            for (int i = mObservers.size() - 1; i >= 0; i--) {
+                mObservers.get(i).onItemRangeInserted(positionStart, itemCount);
+            }
+        }
+
+        public void notifyItemRangeRemoved(int positionStart, int itemCount) {
+            // since onItemRangeRemoved() is implemented by the app, it could do anything, including
+            // removing itself from {@link mObservers} - and that could cause problems if
+            // an iterator is used on the ArrayList {@link mObservers}.
+            // to avoid such problems, just march thru the list in the reverse order.
+            for (int i = mObservers.size() - 1; i >= 0; i--) {
+                mObservers.get(i).onItemRangeRemoved(positionStart, itemCount);
+            }
+        }
+
+        public void notifyItemMoved(int fromPosition, int toPosition) {
+            for (int i = mObservers.size() - 1; i >= 0; i--) {
+                mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1);
+            }
+        }
+    }
+
+    /**
+     * This is public so that the CREATOR can be access on cold launch.
+     * @hide
+     */
+    public static class SavedState extends AbsSavedState {
+
+        Parcelable mLayoutState;
+
+        /**
+         * called by CREATOR
+         */
+        SavedState(Parcel in) {
+            super(in);
+            mLayoutState = in.readParcelable(LayoutManager.class.getClassLoader());
+        }
+
+        /**
+         * Called by onSaveInstanceState
+         */
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeParcelable(mLayoutState, 0);
+        }
+
+        void copyFrom(SavedState other) {
+            mLayoutState = other.mLayoutState;
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
+                    @Override
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in);
+                    }
+
+                    @Override
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
+    }
+    /**
+     * <p>Contains useful information about the current RecyclerView state like target scroll
+     * position or view focus. State object can also keep arbitrary data, identified by resource
+     * ids.</p>
+     * <p>Often times, RecyclerView components will need to pass information between each other.
+     * To provide a well defined data bus between components, RecyclerView passes the same State
+     * object to component callbacks and these components can use it to exchange data.</p>
+     * <p>If you implement custom components, you can use State's put/get/remove methods to pass
+     * data between your components without needing to manage their lifecycles.</p>
+     */
+    public static class State {
+        static final int STEP_START = 1;
+        static final int STEP_LAYOUT = 1 << 1;
+        static final int STEP_ANIMATIONS = 1 << 2;
+
+        void assertLayoutStep(int accepted) {
+            if ((accepted & mLayoutStep) == 0) {
+                throw new IllegalStateException("Layout state should be one of "
+                        + Integer.toBinaryString(accepted) + " but it is "
+                        + Integer.toBinaryString(mLayoutStep));
+            }
+        }
+
+
+        /** Owned by SmoothScroller */
+        private int mTargetPosition = RecyclerView.NO_POSITION;
+
+        private SparseArray<Object> mData;
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        // Fields below are carried from one layout pass to the next
+        ////////////////////////////////////////////////////////////////////////////////////////////
+
+        /**
+         * Number of items adapter had in the previous layout.
+         */
+        int mPreviousLayoutItemCount = 0;
+
+        /**
+         * Number of items that were NOT laid out but has been deleted from the adapter after the
+         * previous layout.
+         */
+        int mDeletedInvisibleItemCountSincePreviousLayout = 0;
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        // Fields below must be updated or cleared before they are used (generally before a pass)
+        ////////////////////////////////////////////////////////////////////////////////////////////
+
+        @IntDef(flag = true, value = {
+                STEP_START, STEP_LAYOUT, STEP_ANIMATIONS
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface LayoutState {}
+
+        @LayoutState
+        int mLayoutStep = STEP_START;
+
+        /**
+         * Number of items adapter has.
+         */
+        int mItemCount = 0;
+
+        boolean mStructureChanged = false;
+
+        boolean mInPreLayout = false;
+
+        boolean mTrackOldChangeHolders = false;
+
+        boolean mIsMeasuring = false;
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        // Fields below are always reset outside of the pass (or passes) that use them
+        ////////////////////////////////////////////////////////////////////////////////////////////
+
+        boolean mRunSimpleAnimations = false;
+
+        boolean mRunPredictiveAnimations = false;
+
+        /**
+         * This data is saved before a layout calculation happens. After the layout is finished,
+         * if the previously focused view has been replaced with another view for the same item, we
+         * move the focus to the new item automatically.
+         */
+        int mFocusedItemPosition;
+        long mFocusedItemId;
+        // when a sub child has focus, record its id and see if we can directly request focus on
+        // that one instead
+        int mFocusedSubChildId;
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+
+        State reset() {
+            mTargetPosition = RecyclerView.NO_POSITION;
+            if (mData != null) {
+                mData.clear();
+            }
+            mItemCount = 0;
+            mStructureChanged = false;
+            mIsMeasuring = false;
+            return this;
+        }
+
+        /**
+         * Prepare for a prefetch occurring on the RecyclerView in between traversals, potentially
+         * prior to any layout passes.
+         *
+         * <p>Don't touch any state stored between layout passes, only reset per-layout state, so
+         * that Recycler#getViewForPosition() can function safely.</p>
+         */
+        void prepareForNestedPrefetch(Adapter adapter) {
+            mLayoutStep = STEP_START;
+            mItemCount = adapter.getItemCount();
+            mStructureChanged = false;
+            mInPreLayout = false;
+            mTrackOldChangeHolders = false;
+            mIsMeasuring = false;
+        }
+
+        /**
+         * Returns true if the RecyclerView is currently measuring the layout. This value is
+         * {@code true} only if the LayoutManager opted into the auto measure API and RecyclerView
+         * has non-exact measurement specs.
+         * <p>
+         * Note that if the LayoutManager supports predictive animations and it is calculating the
+         * pre-layout step, this value will be {@code false} even if the RecyclerView is in
+         * {@code onMeasure} call. This is because pre-layout means the previous state of the
+         * RecyclerView and measurements made for that state cannot change the RecyclerView's size.
+         * LayoutManager is always guaranteed to receive another call to
+         * {@link LayoutManager#onLayoutChildren(Recycler, State)} when this happens.
+         *
+         * @return True if the RecyclerView is currently calculating its bounds, false otherwise.
+         */
+        public boolean isMeasuring() {
+            return mIsMeasuring;
+        }
+
+        /**
+         * Returns true if
+         * @return
+         */
+        public boolean isPreLayout() {
+            return mInPreLayout;
+        }
+
+        /**
+         * Returns whether RecyclerView will run predictive animations in this layout pass
+         * or not.
+         *
+         * @return true if RecyclerView is calculating predictive animations to be run at the end
+         *         of the layout pass.
+         */
+        public boolean willRunPredictiveAnimations() {
+            return mRunPredictiveAnimations;
+        }
+
+        /**
+         * Returns whether RecyclerView will run simple animations in this layout pass
+         * or not.
+         *
+         * @return true if RecyclerView is calculating simple animations to be run at the end of
+         *         the layout pass.
+         */
+        public boolean willRunSimpleAnimations() {
+            return mRunSimpleAnimations;
+        }
+
+        /**
+         * Removes the mapping from the specified id, if there was any.
+         * @param resourceId Id of the resource you want to remove. It is suggested to use R.id.* to
+         *                   preserve cross functionality and avoid conflicts.
+         */
+        public void remove(int resourceId) {
+            if (mData == null) {
+                return;
+            }
+            mData.remove(resourceId);
+        }
+
+        /**
+         * Gets the Object mapped from the specified id, or <code>null</code>
+         * if no such data exists.
+         *
+         * @param resourceId Id of the resource you want to remove. It is suggested to use R.id.*
+         *                   to
+         *                   preserve cross functionality and avoid conflicts.
+         */
+        public <T> T get(int resourceId) {
+            if (mData == null) {
+                return null;
+            }
+            return (T) mData.get(resourceId);
+        }
+
+        /**
+         * Adds a mapping from the specified id to the specified value, replacing the previous
+         * mapping from the specified key if there was one.
+         *
+         * @param resourceId Id of the resource you want to add. It is suggested to use R.id.* to
+         *                   preserve cross functionality and avoid conflicts.
+         * @param data       The data you want to associate with the resourceId.
+         */
+        public void put(int resourceId, Object data) {
+            if (mData == null) {
+                mData = new SparseArray<Object>();
+            }
+            mData.put(resourceId, data);
+        }
+
+        /**
+         * If scroll is triggered to make a certain item visible, this value will return the
+         * adapter index of that item.
+         * @return Adapter index of the target item or
+         * {@link RecyclerView#NO_POSITION} if there is no target
+         * position.
+         */
+        public int getTargetScrollPosition() {
+            return mTargetPosition;
+        }
+
+        /**
+         * Returns if current scroll has a target position.
+         * @return true if scroll is being triggered to make a certain position visible
+         * @see #getTargetScrollPosition()
+         */
+        public boolean hasTargetScrollPosition() {
+            return mTargetPosition != RecyclerView.NO_POSITION;
+        }
+
+        /**
+         * @return true if the structure of the data set has changed since the last call to
+         *         onLayoutChildren, false otherwise
+         */
+        public boolean didStructureChange() {
+            return mStructureChanged;
+        }
+
+        /**
+         * Returns the total number of items that can be laid out. Note that this number is not
+         * necessarily equal to the number of items in the adapter, so you should always use this
+         * number for your position calculations and never access the adapter directly.
+         * <p>
+         * RecyclerView listens for Adapter's notify events and calculates the effects of adapter
+         * data changes on existing Views. These calculations are used to decide which animations
+         * should be run.
+         * <p>
+         * To support predictive animations, RecyclerView may rewrite or reorder Adapter changes to
+         * present the correct state to LayoutManager in pre-layout pass.
+         * <p>
+         * For example, a newly added item is not included in pre-layout item count because
+         * pre-layout reflects the contents of the adapter before the item is added. Behind the
+         * scenes, RecyclerView offsets {@link Recycler#getViewForPosition(int)} calls such that
+         * LayoutManager does not know about the new item's existence in pre-layout. The item will
+         * be available in second layout pass and will be included in the item count. Similar
+         * adjustments are made for moved and removed items as well.
+         * <p>
+         * You can get the adapter's item count via {@link LayoutManager#getItemCount()} method.
+         *
+         * @return The number of items currently available
+         * @see LayoutManager#getItemCount()
+         */
+        public int getItemCount() {
+            return mInPreLayout
+                    ? (mPreviousLayoutItemCount - mDeletedInvisibleItemCountSincePreviousLayout)
+                    : mItemCount;
+        }
+
+        @Override
+        public String toString() {
+            return "State{"
+                    + "mTargetPosition=" + mTargetPosition
+                    + ", mData=" + mData
+                    + ", mItemCount=" + mItemCount
+                    + ", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount
+                    + ", mDeletedInvisibleItemCountSincePreviousLayout="
+                    + mDeletedInvisibleItemCountSincePreviousLayout
+                    + ", mStructureChanged=" + mStructureChanged
+                    + ", mInPreLayout=" + mInPreLayout
+                    + ", mRunSimpleAnimations=" + mRunSimpleAnimations
+                    + ", mRunPredictiveAnimations=" + mRunPredictiveAnimations
+                    + '}';
+        }
+    }
+
+    /**
+     * This class defines the behavior of fling if the developer wishes to handle it.
+     * <p>
+     * Subclasses of {@link OnFlingListener} can be used to implement custom fling behavior.
+     *
+     * @see #setOnFlingListener(OnFlingListener)
+     */
+    public abstract static class OnFlingListener {
+
+        /**
+         * Override this to handle a fling given the velocities in both x and y directions.
+         * Note that this method will only be called if the associated {@link LayoutManager}
+         * supports scrolling and the fling is not handled by nested scrolls first.
+         *
+         * @param velocityX the fling velocity on the X axis
+         * @param velocityY the fling velocity on the Y axis
+         *
+         * @return true if the fling washandled, false otherwise.
+         */
+        public abstract boolean onFling(int velocityX, int velocityY);
+    }
+
+    /**
+     * Internal listener that manages items after animations finish. This is how items are
+     * retained (not recycled) during animations, but allowed to be recycled afterwards.
+     * It depends on the contract with the ItemAnimator to call the appropriate dispatch*Finished()
+     * method on the animator's listener when it is done animating any item.
+     */
+    private class ItemAnimatorRestoreListener implements ItemAnimator.ItemAnimatorListener {
+
+        ItemAnimatorRestoreListener() {
+        }
+
+        @Override
+        public void onAnimationFinished(ViewHolder item) {
+            item.setIsRecyclable(true);
+            if (item.mShadowedHolder != null && item.mShadowingHolder == null) { // old vh
+                item.mShadowedHolder = null;
+            }
+            // always null this because an OldViewHolder can never become NewViewHolder w/o being
+            // recycled.
+            item.mShadowingHolder = null;
+            if (!item.shouldBeKeptAsChild()) {
+                if (!removeAnimatingView(item.itemView) && item.isTmpDetached()) {
+                    removeDetachedView(item.itemView, false);
+                }
+            }
+        }
+    }
+
+    /**
+     * This class defines the animations that take place on items as changes are made
+     * to the adapter.
+     *
+     * Subclasses of ItemAnimator can be used to implement custom animations for actions on
+     * ViewHolder items. The RecyclerView will manage retaining these items while they
+     * are being animated, but implementors must call {@link #dispatchAnimationFinished(ViewHolder)}
+     * when a ViewHolder's animation is finished. In other words, there must be a matching
+     * {@link #dispatchAnimationFinished(ViewHolder)} call for each
+     * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) animateAppearance()},
+     * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     * animateChange()}
+     * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) animatePersistence()},
+     * and
+     * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     * animateDisappearance()} call.
+     *
+     * <p>By default, RecyclerView uses {@link DefaultItemAnimator}.</p>
+     *
+     * @see #setItemAnimator(ItemAnimator)
+     */
+    @SuppressWarnings("UnusedParameters")
+    public abstract static class ItemAnimator {
+
+        /**
+         * The Item represented by this ViewHolder is updated.
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_CHANGED = ViewHolder.FLAG_UPDATE;
+
+        /**
+         * The Item represented by this ViewHolder is removed from the adapter.
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_REMOVED = ViewHolder.FLAG_REMOVED;
+
+        /**
+         * Adapter {@link Adapter#notifyDataSetChanged()} has been called and the content
+         * represented by this ViewHolder is invalid.
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_INVALIDATED = ViewHolder.FLAG_INVALID;
+
+        /**
+         * The position of the Item represented by this ViewHolder has been changed. This flag is
+         * not bound to {@link Adapter#notifyItemMoved(int, int)}. It might be set in response to
+         * any adapter change that may have a side effect on this item. (e.g. The item before this
+         * one has been removed from the Adapter).
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_MOVED = ViewHolder.FLAG_MOVED;
+
+        /**
+         * This ViewHolder was not laid out but has been added to the layout in pre-layout state
+         * by the {@link LayoutManager}. This means that the item was already in the Adapter but
+         * invisible and it may become visible in the post layout phase. LayoutManagers may prefer
+         * to add new items in pre-layout to specify their virtual location when they are invisible
+         * (e.g. to specify the item should <i>animate in</i> from below the visible area).
+         * <p>
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         */
+        public static final int FLAG_APPEARED_IN_PRE_LAYOUT =
+                ViewHolder.FLAG_APPEARED_IN_PRE_LAYOUT;
+
+        /**
+         * The set of flags that might be passed to
+         * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         */
+        @IntDef(flag = true, value = {
+                FLAG_CHANGED, FLAG_REMOVED, FLAG_MOVED, FLAG_INVALIDATED,
+                FLAG_APPEARED_IN_PRE_LAYOUT
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface AdapterChanges {}
+        private ItemAnimatorListener mListener = null;
+        private ArrayList<ItemAnimatorFinishedListener> mFinishedListeners =
+                new ArrayList<ItemAnimatorFinishedListener>();
+
+        private long mAddDuration = 120;
+        private long mRemoveDuration = 120;
+        private long mMoveDuration = 250;
+        private long mChangeDuration = 250;
+
+        /**
+         * Gets the current duration for which all move animations will run.
+         *
+         * @return The current move duration
+         */
+        public long getMoveDuration() {
+            return mMoveDuration;
+        }
+
+        /**
+         * Sets the duration for which all move animations will run.
+         *
+         * @param moveDuration The move duration
+         */
+        public void setMoveDuration(long moveDuration) {
+            mMoveDuration = moveDuration;
+        }
+
+        /**
+         * Gets the current duration for which all add animations will run.
+         *
+         * @return The current add duration
+         */
+        public long getAddDuration() {
+            return mAddDuration;
+        }
+
+        /**
+         * Sets the duration for which all add animations will run.
+         *
+         * @param addDuration The add duration
+         */
+        public void setAddDuration(long addDuration) {
+            mAddDuration = addDuration;
+        }
+
+        /**
+         * Gets the current duration for which all remove animations will run.
+         *
+         * @return The current remove duration
+         */
+        public long getRemoveDuration() {
+            return mRemoveDuration;
+        }
+
+        /**
+         * Sets the duration for which all remove animations will run.
+         *
+         * @param removeDuration The remove duration
+         */
+        public void setRemoveDuration(long removeDuration) {
+            mRemoveDuration = removeDuration;
+        }
+
+        /**
+         * Gets the current duration for which all change animations will run.
+         *
+         * @return The current change duration
+         */
+        public long getChangeDuration() {
+            return mChangeDuration;
+        }
+
+        /**
+         * Sets the duration for which all change animations will run.
+         *
+         * @param changeDuration The change duration
+         */
+        public void setChangeDuration(long changeDuration) {
+            mChangeDuration = changeDuration;
+        }
+
+        /**
+         * Internal only:
+         * Sets the listener that must be called when the animator is finished
+         * animating the item (or immediately if no animation happens). This is set
+         * internally and is not intended to be set by external code.
+         *
+         * @param listener The listener that must be called.
+         */
+        void setListener(ItemAnimatorListener listener) {
+            mListener = listener;
+        }
+
+        /**
+         * Called by the RecyclerView before the layout begins. Item animator should record
+         * necessary information about the View before it is potentially rebound, moved or removed.
+         * <p>
+         * The data returned from this method will be passed to the related <code>animate**</code>
+         * methods.
+         * <p>
+         * Note that this method may be called after pre-layout phase if LayoutManager adds new
+         * Views to the layout in pre-layout pass.
+         * <p>
+         * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of
+         * the View and the adapter change flags.
+         *
+         * @param state       The current State of RecyclerView which includes some useful data
+         *                    about the layout that will be calculated.
+         * @param viewHolder  The ViewHolder whose information should be recorded.
+         * @param changeFlags Additional information about what changes happened in the Adapter
+         *                    about the Item represented by this ViewHolder. For instance, if
+         *                    item is deleted from the adapter, {@link #FLAG_REMOVED} will be set.
+         * @param payloads    The payload list that was previously passed to
+         *                    {@link Adapter#notifyItemChanged(int, Object)} or
+         *                    {@link Adapter#notifyItemRangeChanged(int, int, Object)}.
+         *
+         * @return An ItemHolderInfo instance that preserves necessary information about the
+         * ViewHolder. This object will be passed back to related <code>animate**</code> methods
+         * after layout is complete.
+         *
+         * @see #recordPostLayoutInformation(State, ViewHolder)
+         * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         */
+        public @NonNull ItemHolderInfo recordPreLayoutInformation(@NonNull State state,
+                @NonNull ViewHolder viewHolder, @AdapterChanges int changeFlags,
+                @NonNull List<Object> payloads) {
+            return obtainHolderInfo().setFrom(viewHolder);
+        }
+
+        /**
+         * Called by the RecyclerView after the layout is complete. Item animator should record
+         * necessary information about the View's final state.
+         * <p>
+         * The data returned from this method will be passed to the related <code>animate**</code>
+         * methods.
+         * <p>
+         * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of
+         * the View.
+         *
+         * @param state      The current State of RecyclerView which includes some useful data about
+         *                   the layout that will be calculated.
+         * @param viewHolder The ViewHolder whose information should be recorded.
+         *
+         * @return An ItemHolderInfo that preserves necessary information about the ViewHolder.
+         * This object will be passed back to related <code>animate**</code> methods when
+         * RecyclerView decides how items should be animated.
+         *
+         * @see #recordPreLayoutInformation(State, ViewHolder, int, List)
+         * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         */
+        public @NonNull ItemHolderInfo recordPostLayoutInformation(@NonNull State state,
+                @NonNull ViewHolder viewHolder) {
+            return obtainHolderInfo().setFrom(viewHolder);
+        }
+
+        /**
+         * Called by the RecyclerView when a ViewHolder has disappeared from the layout.
+         * <p>
+         * This means that the View was a child of the LayoutManager when layout started but has
+         * been removed by the LayoutManager. It might have been removed from the adapter or simply
+         * become invisible due to other factors. You can distinguish these two cases by checking
+         * the change flags that were passed to
+         * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * <p>
+         * Note that when a ViewHolder both changes and disappears in the same layout pass, the
+         * animation callback method which will be called by the RecyclerView depends on the
+         * ItemAnimator's decision whether to re-use the same ViewHolder or not, and also the
+         * LayoutManager's decision whether to layout the changed version of a disappearing
+         * ViewHolder or not. RecyclerView will call
+         * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange} instead of {@code animateDisappearance} if and only if the ItemAnimator
+         * returns {@code false} from
+         * {@link #canReuseUpdatedViewHolder(ViewHolder) canReuseUpdatedViewHolder} and the
+         * LayoutManager lays out a new disappearing view that holds the updated information.
+         * Built-in LayoutManagers try to avoid laying out updated versions of disappearing views.
+         * <p>
+         * If LayoutManager supports predictive animations, it might provide a target disappear
+         * location for the View by laying it out in that location. When that happens,
+         * RecyclerView will call {@link #recordPostLayoutInformation(State, ViewHolder)} and the
+         * response of that call will be passed to this method as the <code>postLayoutInfo</code>.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+         * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+         * decides not to animate the view).
+         *
+         * @param viewHolder    The ViewHolder which should be animated
+         * @param preLayoutInfo The information that was returned from
+         *                      {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * @param postLayoutInfo The information that was returned from
+         *                       {@link #recordPostLayoutInformation(State, ViewHolder)}. Might be
+         *                       null if the LayoutManager did not layout the item.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animateDisappearance(@NonNull ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo);
+
+        /**
+         * Called by the RecyclerView when a ViewHolder is added to the layout.
+         * <p>
+         * In detail, this means that the ViewHolder was <b>not</b> a child when the layout started
+         * but has  been added by the LayoutManager. It might be newly added to the adapter or
+         * simply become visible due to other factors.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+         * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+         * decides not to animate the view).
+         *
+         * @param viewHolder     The ViewHolder which should be animated
+         * @param preLayoutInfo  The information that was returned from
+         *                       {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *                       Might be null if Item was just added to the adapter or
+         *                       LayoutManager does not support predictive animations or it could
+         *                       not predict that this ViewHolder will become visible.
+         * @param postLayoutInfo The information that was returned from {@link
+         *                       #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animateAppearance(@NonNull ViewHolder viewHolder,
+                @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+        /**
+         * Called by the RecyclerView when a ViewHolder is present in both before and after the
+         * layout and RecyclerView has not received a {@link Adapter#notifyItemChanged(int)} call
+         * for it or a {@link Adapter#notifyDataSetChanged()} call.
+         * <p>
+         * This ViewHolder still represents the same data that it was representing when the layout
+         * started but its position / size may be changed by the LayoutManager.
+         * <p>
+         * If the Item's layout position didn't change, RecyclerView still calls this method because
+         * it does not track this information (or does not necessarily know that an animation is
+         * not required). Your ItemAnimator should handle this case and if there is nothing to
+         * animate, it should call {@link #dispatchAnimationFinished(ViewHolder)} and return
+         * <code>false</code>.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation
+         * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it
+         * decides not to animate the view).
+         *
+         * @param viewHolder     The ViewHolder which should be animated
+         * @param preLayoutInfo  The information that was returned from
+         *                       {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * @param postLayoutInfo The information that was returned from {@link
+         *                       #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animatePersistence(@NonNull ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+        /**
+         * Called by the RecyclerView when an adapter item is present both before and after the
+         * layout and RecyclerView has received a {@link Adapter#notifyItemChanged(int)} call
+         * for it. This method may also be called when
+         * {@link Adapter#notifyDataSetChanged()} is called and adapter has stable ids so that
+         * RecyclerView could still rebind views to the same ViewHolders. If viewType changes when
+         * {@link Adapter#notifyDataSetChanged()} is called, this method <b>will not</b> be called,
+         * instead, {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)} will be
+         * called for the new ViewHolder and the old one will be recycled.
+         * <p>
+         * If this method is called due to a {@link Adapter#notifyDataSetChanged()} call, there is
+         * a good possibility that item contents didn't really change but it is rebound from the
+         * adapter. {@link DefaultItemAnimator} will skip animating the View if its location on the
+         * screen didn't change and your animator should handle this case as well and avoid creating
+         * unnecessary animations.
+         * <p>
+         * When an item is updated, ItemAnimator has a chance to ask RecyclerView to keep the
+         * previous presentation of the item as-is and supply a new ViewHolder for the updated
+         * presentation (see: {@link #canReuseUpdatedViewHolder(ViewHolder, List)}.
+         * This is useful if you don't know the contents of the Item and would like
+         * to cross-fade the old and the new one ({@link DefaultItemAnimator} uses this technique).
+         * <p>
+         * When you are writing a custom item animator for your layout, it might be more performant
+         * and elegant to re-use the same ViewHolder and animate the content changes manually.
+         * <p>
+         * When {@link Adapter#notifyItemChanged(int)} is called, the Item's view type may change.
+         * If the Item's view type has changed or ItemAnimator returned <code>false</code> for
+         * this ViewHolder when {@link #canReuseUpdatedViewHolder(ViewHolder, List)} was called, the
+         * <code>oldHolder</code> and <code>newHolder</code> will be different ViewHolder instances
+         * which represent the same Item. In that case, only the new ViewHolder is visible
+         * to the LayoutManager but RecyclerView keeps old ViewHolder attached for animations.
+         * <p>
+         * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} for each distinct
+         * ViewHolder when their animation is complete
+         * (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it decides not to
+         * animate the view).
+         * <p>
+         *  If oldHolder and newHolder are the same instance, you should call
+         * {@link #dispatchAnimationFinished(ViewHolder)} <b>only once</b>.
+         * <p>
+         * Note that when a ViewHolder both changes and disappears in the same layout pass, the
+         * animation callback method which will be called by the RecyclerView depends on the
+         * ItemAnimator's decision whether to re-use the same ViewHolder or not, and also the
+         * LayoutManager's decision whether to layout the changed version of a disappearing
+         * ViewHolder or not. RecyclerView will call
+         * {@code animateChange} instead of
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance} if and only if the ItemAnimator returns {@code false} from
+         * {@link #canReuseUpdatedViewHolder(ViewHolder) canReuseUpdatedViewHolder} and the
+         * LayoutManager lays out a new disappearing view that holds the updated information.
+         * Built-in LayoutManagers try to avoid laying out updated versions of disappearing views.
+         *
+         * @param oldHolder     The ViewHolder before the layout is started, might be the same
+         *                      instance with newHolder.
+         * @param newHolder     The ViewHolder after the layout is finished, might be the same
+         *                      instance with oldHolder.
+         * @param preLayoutInfo  The information that was returned from
+         *                       {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         * @param postLayoutInfo The information that was returned from {@link
+         *                       #recordPreLayoutInformation(State, ViewHolder, int, List)}.
+         *
+         * @return true if a later call to {@link #runPendingAnimations()} is requested,
+         * false otherwise.
+         */
+        public abstract boolean animateChange(@NonNull ViewHolder oldHolder,
+                @NonNull ViewHolder newHolder,
+                @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo);
+
+        @AdapterChanges static int buildAdapterChangeFlagsForAnimations(ViewHolder viewHolder) {
+            int flags = viewHolder.mFlags & (FLAG_INVALIDATED | FLAG_REMOVED | FLAG_CHANGED);
+            if (viewHolder.isInvalid()) {
+                return FLAG_INVALIDATED;
+            }
+            if ((flags & FLAG_INVALIDATED) == 0) {
+                final int oldPos = viewHolder.getOldPosition();
+                final int pos = viewHolder.getAdapterPosition();
+                if (oldPos != NO_POSITION && pos != NO_POSITION && oldPos != pos) {
+                    flags |= FLAG_MOVED;
+                }
+            }
+            return flags;
+        }
+
+        /**
+         * Called when there are pending animations waiting to be started. This state
+         * is governed by the return values from
+         * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateAppearance()},
+         * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange()}
+         * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animatePersistence()}, and
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance()}, which inform the RecyclerView that the ItemAnimator wants to be
+         * called later to start the associated animations. runPendingAnimations() will be scheduled
+         * to be run on the next frame.
+         */
+        public abstract void runPendingAnimations();
+
+        /**
+         * Method called when an animation on a view should be ended immediately.
+         * This could happen when other events, like scrolling, occur, so that
+         * animating views can be quickly put into their proper end locations.
+         * Implementations should ensure that any animations running on the item
+         * are canceled and affected properties are set to their end values.
+         * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
+         * animation since the animations are effectively done when this method is called.
+         *
+         * @param item The item for which an animation should be stopped.
+         */
+        public abstract void endAnimation(ViewHolder item);
+
+        /**
+         * Method called when all item animations should be ended immediately.
+         * This could happen when other events, like scrolling, occur, so that
+         * animating views can be quickly put into their proper end locations.
+         * Implementations should ensure that any animations running on any items
+         * are canceled and affected properties are set to their end values.
+         * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished
+         * animation since the animations are effectively done when this method is called.
+         */
+        public abstract void endAnimations();
+
+        /**
+         * Method which returns whether there are any item animations currently running.
+         * This method can be used to determine whether to delay other actions until
+         * animations end.
+         *
+         * @return true if there are any item animations currently running, false otherwise.
+         */
+        public abstract boolean isRunning();
+
+        /**
+         * Method to be called by subclasses when an animation is finished.
+         * <p>
+         * For each call RecyclerView makes to
+         * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateAppearance()},
+         * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animatePersistence()}, or
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance()}, there
+         * should
+         * be a matching {@link #dispatchAnimationFinished(ViewHolder)} call by the subclass.
+         * <p>
+         * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange()}, subclass should call this method for both the <code>oldHolder</code>
+         * and <code>newHolder</code>  (if they are not the same instance).
+         *
+         * @param viewHolder The ViewHolder whose animation is finished.
+         * @see #onAnimationFinished(ViewHolder)
+         */
+        public final void dispatchAnimationFinished(ViewHolder viewHolder) {
+            onAnimationFinished(viewHolder);
+            if (mListener != null) {
+                mListener.onAnimationFinished(viewHolder);
+            }
+        }
+
+        /**
+         * Called after {@link #dispatchAnimationFinished(ViewHolder)} is called by the
+         * ItemAnimator.
+         *
+         * @param viewHolder The ViewHolder whose animation is finished. There might still be other
+         *                   animations running on this ViewHolder.
+         * @see #dispatchAnimationFinished(ViewHolder)
+         */
+        public void onAnimationFinished(ViewHolder viewHolder) {
+        }
+
+        /**
+         * Method to be called by subclasses when an animation is started.
+         * <p>
+         * For each call RecyclerView makes to
+         * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateAppearance()},
+         * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animatePersistence()}, or
+         * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateDisappearance()}, there should be a matching
+         * {@link #dispatchAnimationStarted(ViewHolder)} call by the subclass.
+         * <p>
+         * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)
+         * animateChange()}, subclass should call this method for both the <code>oldHolder</code>
+         * and <code>newHolder</code> (if they are not the same instance).
+         * <p>
+         * If your ItemAnimator decides not to animate a ViewHolder, it should call
+         * {@link #dispatchAnimationFinished(ViewHolder)} <b>without</b> calling
+         * {@link #dispatchAnimationStarted(ViewHolder)}.
+         *
+         * @param viewHolder The ViewHolder whose animation is starting.
+         * @see #onAnimationStarted(ViewHolder)
+         */
+        public final void dispatchAnimationStarted(ViewHolder viewHolder) {
+            onAnimationStarted(viewHolder);
+        }
+
+        /**
+         * Called when a new animation is started on the given ViewHolder.
+         *
+         * @param viewHolder The ViewHolder which started animating. Note that the ViewHolder
+         *                   might already be animating and this might be another animation.
+         * @see #dispatchAnimationStarted(ViewHolder)
+         */
+        public void onAnimationStarted(ViewHolder viewHolder) {
+
+        }
+
+        /**
+         * Like {@link #isRunning()}, this method returns whether there are any item
+         * animations currently running. Additionally, the listener passed in will be called
+         * when there are no item animations running, either immediately (before the method
+         * returns) if no animations are currently running, or when the currently running
+         * animations are {@link #dispatchAnimationsFinished() finished}.
+         *
+         * <p>Note that the listener is transient - it is either called immediately and not
+         * stored at all, or stored only until it is called when running animations
+         * are finished sometime later.</p>
+         *
+         * @param listener A listener to be called immediately if no animations are running
+         * or later when currently-running animations have finished. A null listener is
+         * equivalent to calling {@link #isRunning()}.
+         * @return true if there are any item animations currently running, false otherwise.
+         */
+        public final boolean isRunning(ItemAnimatorFinishedListener listener) {
+            boolean running = isRunning();
+            if (listener != null) {
+                if (!running) {
+                    listener.onAnimationsFinished();
+                } else {
+                    mFinishedListeners.add(listener);
+                }
+            }
+            return running;
+        }
+
+        /**
+         * When an item is changed, ItemAnimator can decide whether it wants to re-use
+         * the same ViewHolder for animations or RecyclerView should create a copy of the
+         * item and ItemAnimator will use both to run the animation (e.g. cross-fade).
+         * <p>
+         * Note that this method will only be called if the {@link ViewHolder} still has the same
+         * type ({@link Adapter#getItemViewType(int)}). Otherwise, ItemAnimator will always receive
+         * both {@link ViewHolder}s in the
+         * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)} method.
+         * <p>
+         * If your application is using change payloads, you can override
+         * {@link #canReuseUpdatedViewHolder(ViewHolder, List)} to decide based on payloads.
+         *
+         * @param viewHolder The ViewHolder which represents the changed item's old content.
+         *
+         * @return True if RecyclerView should just rebind to the same ViewHolder or false if
+         *         RecyclerView should create a new ViewHolder and pass this ViewHolder to the
+         *         ItemAnimator to animate. Default implementation returns <code>true</code>.
+         *
+         * @see #canReuseUpdatedViewHolder(ViewHolder, List)
+         */
+        public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder) {
+            return true;
+        }
+
+        /**
+         * When an item is changed, ItemAnimator can decide whether it wants to re-use
+         * the same ViewHolder for animations or RecyclerView should create a copy of the
+         * item and ItemAnimator will use both to run the animation (e.g. cross-fade).
+         * <p>
+         * Note that this method will only be called if the {@link ViewHolder} still has the same
+         * type ({@link Adapter#getItemViewType(int)}). Otherwise, ItemAnimator will always receive
+         * both {@link ViewHolder}s in the
+         * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)} method.
+         *
+         * @param viewHolder The ViewHolder which represents the changed item's old content.
+         * @param payloads A non-null list of merged payloads that were sent with change
+         *                 notifications. Can be empty if the adapter is invalidated via
+         *                 {@link RecyclerView.Adapter#notifyDataSetChanged()}. The same list of
+         *                 payloads will be passed into
+         *                 {@link RecyclerView.Adapter#onBindViewHolder(ViewHolder, int, List)}
+         *                 method <b>if</b> this method returns <code>true</code>.
+         *
+         * @return True if RecyclerView should just rebind to the same ViewHolder or false if
+         *         RecyclerView should create a new ViewHolder and pass this ViewHolder to the
+         *         ItemAnimator to animate. Default implementation calls
+         *         {@link #canReuseUpdatedViewHolder(ViewHolder)}.
+         *
+         * @see #canReuseUpdatedViewHolder(ViewHolder)
+         */
+        public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder,
+                @NonNull List<Object> payloads) {
+            return canReuseUpdatedViewHolder(viewHolder);
+        }
+
+        /**
+         * This method should be called by ItemAnimator implementations to notify
+         * any listeners that all pending and active item animations are finished.
+         */
+        public final void dispatchAnimationsFinished() {
+            final int count = mFinishedListeners.size();
+            for (int i = 0; i < count; ++i) {
+                mFinishedListeners.get(i).onAnimationsFinished();
+            }
+            mFinishedListeners.clear();
+        }
+
+        /**
+         * Returns a new {@link ItemHolderInfo} which will be used to store information about the
+         * ViewHolder. This information will later be passed into <code>animate**</code> methods.
+         * <p>
+         * You can override this method if you want to extend {@link ItemHolderInfo} and provide
+         * your own instances.
+         *
+         * @return A new {@link ItemHolderInfo}.
+         */
+        public ItemHolderInfo obtainHolderInfo() {
+            return new ItemHolderInfo();
+        }
+
+        /**
+         * The interface to be implemented by listeners to animation events from this
+         * ItemAnimator. This is used internally and is not intended for developers to
+         * create directly.
+         */
+        interface ItemAnimatorListener {
+            void onAnimationFinished(ViewHolder item);
+        }
+
+        /**
+         * This interface is used to inform listeners when all pending or running animations
+         * in an ItemAnimator are finished. This can be used, for example, to delay an action
+         * in a data set until currently-running animations are complete.
+         *
+         * @see #isRunning(ItemAnimatorFinishedListener)
+         */
+        public interface ItemAnimatorFinishedListener {
+            /**
+             * Notifies when all pending or running animations in an ItemAnimator are finished.
+             */
+            void onAnimationsFinished();
+        }
+
+        /**
+         * A simple data structure that holds information about an item's bounds.
+         * This information is used in calculating item animations. Default implementation of
+         * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)} and
+         * {@link #recordPostLayoutInformation(RecyclerView.State, ViewHolder)} returns this data
+         * structure. You can extend this class if you would like to keep more information about
+         * the Views.
+         * <p>
+         * If you want to provide your own implementation but still use `super` methods to record
+         * basic information, you can override {@link #obtainHolderInfo()} to provide your own
+         * instances.
+         */
+        public static class ItemHolderInfo {
+
+            /**
+             * The left edge of the View (excluding decorations)
+             */
+            public int left;
+
+            /**
+             * The top edge of the View (excluding decorations)
+             */
+            public int top;
+
+            /**
+             * The right edge of the View (excluding decorations)
+             */
+            public int right;
+
+            /**
+             * The bottom edge of the View (excluding decorations)
+             */
+            public int bottom;
+
+            /**
+             * The change flags that were passed to
+             * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)}.
+             */
+            @AdapterChanges
+            public int changeFlags;
+
+            public ItemHolderInfo() {
+            }
+
+            /**
+             * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from
+             * the given ViewHolder. Clears all {@link #changeFlags}.
+             *
+             * @param holder The ViewHolder whose bounds should be copied.
+             * @return This {@link ItemHolderInfo}
+             */
+            public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder) {
+                return setFrom(holder, 0);
+            }
+
+            /**
+             * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from
+             * the given ViewHolder and sets the {@link #changeFlags} to the given flags parameter.
+             *
+             * @param holder The ViewHolder whose bounds should be copied.
+             * @param flags  The adapter change flags that were passed into
+             *               {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int,
+             *               List)}.
+             * @return This {@link ItemHolderInfo}
+             */
+            public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder,
+                    @AdapterChanges int flags) {
+                final View view = holder.itemView;
+                this.left = view.getLeft();
+                this.top = view.getTop();
+                this.right = view.getRight();
+                this.bottom = view.getBottom();
+                return this;
+            }
+        }
+    }
+
+    @Override
+    protected int getChildDrawingOrder(int childCount, int i) {
+        if (mChildDrawingOrderCallback == null) {
+            return super.getChildDrawingOrder(childCount, i);
+        } else {
+            return mChildDrawingOrderCallback.onGetChildDrawingOrder(childCount, i);
+        }
+    }
+
+    /**
+     * A callback interface that can be used to alter the drawing order of RecyclerView children.
+     * <p>
+     * It works using the {@link ViewGroup#getChildDrawingOrder(int, int)} method, so any case
+     * that applies to that method also applies to this callback. For example, changing the drawing
+     * order of two views will not have any effect if their elevation values are different since
+     * elevation overrides the result of this callback.
+     */
+    public interface ChildDrawingOrderCallback {
+        /**
+         * Returns the index of the child to draw for this iteration. Override this
+         * if you want to change the drawing order of children. By default, it
+         * returns i.
+         *
+         * @param i The current iteration.
+         * @return The index of the child to draw this iteration.
+         *
+         * @see RecyclerView#setChildDrawingOrderCallback(RecyclerView.ChildDrawingOrderCallback)
+         */
+        int onGetChildDrawingOrder(int childCount, int i);
+    }
+}
diff --git a/core/java/com/android/internal/widget/RecyclerViewAccessibilityDelegate.java b/core/java/com/android/internal/widget/RecyclerViewAccessibilityDelegate.java
new file mode 100644
index 0000000..282da64
--- /dev/null
+++ b/core/java/com/android/internal/widget/RecyclerViewAccessibilityDelegate.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 com.android.internal.widget;
+
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * The AccessibilityDelegate used by RecyclerView.
+ * <p>
+ * This class handles basic accessibility actions and delegates them to LayoutManager.
+ */
+public class RecyclerViewAccessibilityDelegate extends AccessibilityDelegate {
+    final RecyclerView mRecyclerView;
+
+
+    public RecyclerViewAccessibilityDelegate(RecyclerView recyclerView) {
+        mRecyclerView = recyclerView;
+    }
+
+    boolean shouldIgnore() {
+        return mRecyclerView.hasPendingAdapterUpdates();
+    }
+
+    @Override
+    public boolean performAccessibilityAction(View host, int action, Bundle args) {
+        if (super.performAccessibilityAction(host, action, args)) {
+            return true;
+        }
+        if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) {
+            return mRecyclerView.getLayoutManager().performAccessibilityAction(action, args);
+        }
+
+        return false;
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(host, info);
+        info.setClassName(RecyclerView.class.getName());
+        if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) {
+            mRecyclerView.getLayoutManager().onInitializeAccessibilityNodeInfo(info);
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(host, event);
+        event.setClassName(RecyclerView.class.getName());
+        if (host instanceof RecyclerView && !shouldIgnore()) {
+            RecyclerView rv = (RecyclerView) host;
+            if (rv.getLayoutManager() != null) {
+                rv.getLayoutManager().onInitializeAccessibilityEvent(event);
+            }
+        }
+    }
+
+    /**
+     * Gets the AccessibilityDelegate for an individual item in the RecyclerView.
+     * A basic item delegate is provided by default, but you can override this
+     * method to provide a custom per-item delegate.
+     */
+    public AccessibilityDelegate getItemDelegate() {
+        return mItemDelegate;
+    }
+
+    final AccessibilityDelegate mItemDelegate = new AccessibilityDelegate() {
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(host, info);
+            if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) {
+                mRecyclerView.getLayoutManager()
+                        .onInitializeAccessibilityNodeInfoForItem(host, info);
+            }
+        }
+
+        @Override
+        public boolean performAccessibilityAction(View host, int action, Bundle args) {
+            if (super.performAccessibilityAction(host, action, args)) {
+                return true;
+            }
+            if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) {
+                return mRecyclerView.getLayoutManager()
+                        .performAccessibilityActionForItem(host, action, args);
+            }
+            return false;
+        }
+    };
+}
+
diff --git a/core/java/com/android/internal/widget/ScrollbarHelper.java b/core/java/com/android/internal/widget/ScrollbarHelper.java
new file mode 100644
index 0000000..ae34e4c
--- /dev/null
+++ b/core/java/com/android/internal/widget/ScrollbarHelper.java
@@ -0,0 +1,99 @@
+/*
+ * 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.widget;
+
+import android.view.View;
+
+/**
+ * A helper class to do scroll offset calculations.
+ */
+class ScrollbarHelper {
+
+    /**
+     * @param startChild View closest to start of the list. (top or left)
+     * @param endChild   View closest to end of the list (bottom or right)
+     */
+    static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
+            View startChild, View endChild, RecyclerView.LayoutManager lm,
+            boolean smoothScrollbarEnabled, boolean reverseLayout) {
+        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
+                || endChild == null) {
+            return 0;
+        }
+        final int minPosition = Math.min(lm.getPosition(startChild),
+                lm.getPosition(endChild));
+        final int maxPosition = Math.max(lm.getPosition(startChild),
+                lm.getPosition(endChild));
+        final int itemsBefore = reverseLayout
+                ? Math.max(0, state.getItemCount() - maxPosition - 1)
+                : Math.max(0, minPosition);
+        if (!smoothScrollbarEnabled) {
+            return itemsBefore;
+        }
+        final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild)
+                - orientation.getDecoratedStart(startChild));
+        final int itemRange = Math.abs(lm.getPosition(startChild)
+                - lm.getPosition(endChild)) + 1;
+        final float avgSizePerRow = (float) laidOutArea / itemRange;
+
+        return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
+                - orientation.getDecoratedStart(startChild)));
+    }
+
+    /**
+     * @param startChild View closest to start of the list. (top or left)
+     * @param endChild   View closest to end of the list (bottom or right)
+     */
+    static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation,
+            View startChild, View endChild, RecyclerView.LayoutManager lm,
+            boolean smoothScrollbarEnabled) {
+        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
+                || endChild == null) {
+            return 0;
+        }
+        if (!smoothScrollbarEnabled) {
+            return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1;
+        }
+        final int extend = orientation.getDecoratedEnd(endChild)
+                - orientation.getDecoratedStart(startChild);
+        return Math.min(orientation.getTotalSpace(), extend);
+    }
+
+    /**
+     * @param startChild View closest to start of the list. (top or left)
+     * @param endChild   View closest to end of the list (bottom or right)
+     */
+    static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation,
+            View startChild, View endChild, RecyclerView.LayoutManager lm,
+            boolean smoothScrollbarEnabled) {
+        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null
+                || endChild == null) {
+            return 0;
+        }
+        if (!smoothScrollbarEnabled) {
+            return state.getItemCount();
+        }
+        // smooth scrollbar enabled. try to estimate better.
+        final int laidOutArea = orientation.getDecoratedEnd(endChild)
+                - orientation.getDecoratedStart(startChild);
+        final int laidOutRange = Math.abs(lm.getPosition(startChild)
+                - lm.getPosition(endChild))
+                + 1;
+        // estimate a size for full list.
+        return (int) ((float) laidOutArea / laidOutRange * state.getItemCount());
+    }
+}
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 4466575..311bfac 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -471,7 +471,7 @@
                 if (mIconView != null) {
                     mIconView.setContentDescription(tab.getContentDescription());
                 }
-                setTooltip(hasText? null : tab.getContentDescription());
+                setTooltipText(hasText? null : tab.getContentDescription());
             }
         }
 
diff --git a/core/java/com/android/internal/widget/ScrollingView.java b/core/java/com/android/internal/widget/ScrollingView.java
new file mode 100644
index 0000000..a0205e7
--- /dev/null
+++ b/core/java/com/android/internal/widget/ScrollingView.java
@@ -0,0 +1,134 @@
+/*
+ * 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.widget;
+
+/**
+ * An interface that can be implemented by Views to provide scroll related APIs.
+ */
+public interface ScrollingView {
+    /**
+     * <p>Compute the horizontal range that the horizontal scrollbar
+     * represents.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the
+     * units used by {@link #computeHorizontalScrollExtent()} and
+     * {@link #computeHorizontalScrollOffset()}.</p>
+     *
+     * <p>The default range is the drawing width of this view.</p>
+     *
+     * @return the total horizontal range represented by the horizontal
+     *         scrollbar
+     *
+     * @see #computeHorizontalScrollExtent()
+     * @see #computeHorizontalScrollOffset()
+     * @see android.widget.ScrollBarDrawable
+     */
+    int computeHorizontalScrollRange();
+
+    /**
+     * <p>Compute the horizontal offset of the horizontal scrollbar's thumb
+     * within the horizontal range. This value is used to compute the position
+     * of the thumb within the scrollbar's track.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the
+     * units used by {@link #computeHorizontalScrollRange()} and
+     * {@link #computeHorizontalScrollExtent()}.</p>
+     *
+     * <p>The default offset is the scroll offset of this view.</p>
+     *
+     * @return the horizontal offset of the scrollbar's thumb
+     *
+     * @see #computeHorizontalScrollRange()
+     * @see #computeHorizontalScrollExtent()
+     * @see android.widget.ScrollBarDrawable
+     */
+    int computeHorizontalScrollOffset();
+
+    /**
+     * <p>Compute the horizontal extent of the horizontal scrollbar's thumb
+     * within the horizontal range. This value is used to compute the length
+     * of the thumb within the scrollbar's track.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the
+     * units used by {@link #computeHorizontalScrollRange()} and
+     * {@link #computeHorizontalScrollOffset()}.</p>
+     *
+     * <p>The default extent is the drawing width of this view.</p>
+     *
+     * @return the horizontal extent of the scrollbar's thumb
+     *
+     * @see #computeHorizontalScrollRange()
+     * @see #computeHorizontalScrollOffset()
+     * @see android.widget.ScrollBarDrawable
+     */
+    int computeHorizontalScrollExtent();
+
+    /**
+     * <p>Compute the vertical range that the vertical scrollbar represents.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the
+     * units used by {@link #computeVerticalScrollExtent()} and
+     * {@link #computeVerticalScrollOffset()}.</p>
+     *
+     * @return the total vertical range represented by the vertical scrollbar
+     *
+     * <p>The default range is the drawing height of this view.</p>
+     *
+     * @see #computeVerticalScrollExtent()
+     * @see #computeVerticalScrollOffset()
+     * @see android.widget.ScrollBarDrawable
+     */
+    int computeVerticalScrollRange();
+
+    /**
+     * <p>Compute the vertical offset of the vertical scrollbar's thumb
+     * within the horizontal range. This value is used to compute the position
+     * of the thumb within the scrollbar's track.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the
+     * units used by {@link #computeVerticalScrollRange()} and
+     * {@link #computeVerticalScrollExtent()}.</p>
+     *
+     * <p>The default offset is the scroll offset of this view.</p>
+     *
+     * @return the vertical offset of the scrollbar's thumb
+     *
+     * @see #computeVerticalScrollRange()
+     * @see #computeVerticalScrollExtent()
+     * @see android.widget.ScrollBarDrawable
+     */
+    int computeVerticalScrollOffset();
+
+    /**
+     * <p>Compute the vertical extent of the vertical scrollbar's thumb
+     * within the vertical range. This value is used to compute the length
+     * of the thumb within the scrollbar's track.</p>
+     *
+     * <p>The range is expressed in arbitrary units that must be the same as the
+     * units used by {@link #computeVerticalScrollRange()} and
+     * {@link #computeVerticalScrollOffset()}.</p>
+     *
+     * <p>The default extent is the drawing height of this view.</p>
+     *
+     * @return the vertical extent of the scrollbar's thumb
+     *
+     * @see #computeVerticalScrollRange()
+     * @see #computeVerticalScrollOffset()
+     * @see android.widget.ScrollBarDrawable
+     */
+    int computeVerticalScrollExtent();
+}
diff --git a/core/java/com/android/internal/widget/SimpleItemAnimator.java b/core/java/com/android/internal/widget/SimpleItemAnimator.java
new file mode 100644
index 0000000..f4cc753
--- /dev/null
+++ b/core/java/com/android/internal/widget/SimpleItemAnimator.java
@@ -0,0 +1,457 @@
+/*
+ * 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.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+import android.view.View;
+
+import com.android.internal.widget.RecyclerView.Adapter;
+import com.android.internal.widget.RecyclerView.ViewHolder;
+
+/**
+ * A wrapper class for ItemAnimator that records View bounds and decides whether it should run
+ * move, change, add or remove animations. This class also replicates the original ItemAnimator
+ * API.
+ * <p>
+ * It uses {@link ItemHolderInfo} to track the bounds information of the Views. If you would like
+ * to
+ * extend this class, you can override {@link #obtainHolderInfo()} method to provide your own info
+ * class that extends {@link ItemHolderInfo}.
+ */
+public abstract class SimpleItemAnimator extends RecyclerView.ItemAnimator {
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "SimpleItemAnimator";
+
+    boolean mSupportsChangeAnimations = true;
+
+    /**
+     * Returns whether this ItemAnimator supports animations of change events.
+     *
+     * @return true if change animations are supported, false otherwise
+     */
+    @SuppressWarnings("unused")
+    public boolean getSupportsChangeAnimations() {
+        return mSupportsChangeAnimations;
+    }
+
+    /**
+     * Sets whether this ItemAnimator supports animations of item change events.
+     * If you set this property to false, actions on the data set which change the
+     * contents of items will not be animated. What those animations do is left
+     * up to the discretion of the ItemAnimator subclass, in its
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation.
+     * The value of this property is true by default.
+     *
+     * @param supportsChangeAnimations true if change animations are supported by
+     *                                 this ItemAnimator, false otherwise. If the property is false,
+     *                                 the ItemAnimator
+     *                                 will not receive a call to
+     *                                 {@link #animateChange(ViewHolder, ViewHolder, int, int, int,
+     *                                 int)} when changes occur.
+     * @see Adapter#notifyItemChanged(int)
+     * @see Adapter#notifyItemRangeChanged(int, int)
+     */
+    public void setSupportsChangeAnimations(boolean supportsChangeAnimations) {
+        mSupportsChangeAnimations = supportsChangeAnimations;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return True if change animations are not supported or the ViewHolder is invalid,
+     * false otherwise.
+     *
+     * @see #setSupportsChangeAnimations(boolean)
+     */
+    @Override
+    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
+        return !mSupportsChangeAnimations || viewHolder.isInvalid();
+    }
+
+    @Override
+    public boolean animateDisappearance(@NonNull ViewHolder viewHolder,
+            @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) {
+        int oldLeft = preLayoutInfo.left;
+        int oldTop = preLayoutInfo.top;
+        View disappearingItemView = viewHolder.itemView;
+        int newLeft = postLayoutInfo == null ? disappearingItemView.getLeft() : postLayoutInfo.left;
+        int newTop = postLayoutInfo == null ? disappearingItemView.getTop() : postLayoutInfo.top;
+        if (!viewHolder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) {
+            disappearingItemView.layout(newLeft, newTop,
+                    newLeft + disappearingItemView.getWidth(),
+                    newTop + disappearingItemView.getHeight());
+            if (DEBUG) {
+                Log.d(TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView);
+            }
+            return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView);
+            }
+            return animateRemove(viewHolder);
+        }
+    }
+
+    @Override
+    public boolean animateAppearance(@NonNull ViewHolder viewHolder,
+            @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) {
+        if (preLayoutInfo != null && (preLayoutInfo.left != postLayoutInfo.left
+                || preLayoutInfo.top != postLayoutInfo.top)) {
+            // slide items in if before/after locations differ
+            if (DEBUG) {
+                Log.d(TAG, "APPEARING: " + viewHolder + " with view " + viewHolder);
+            }
+            return animateMove(viewHolder, preLayoutInfo.left, preLayoutInfo.top,
+                    postLayoutInfo.left, postLayoutInfo.top);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "ADDED: " + viewHolder + " with view " + viewHolder);
+            }
+            return animateAdd(viewHolder);
+        }
+    }
+
+    @Override
+    public boolean animatePersistence(@NonNull ViewHolder viewHolder,
+            @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+        if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
+            if (DEBUG) {
+                Log.d(TAG, "PERSISTENT: " + viewHolder
+                        + " with view " + viewHolder.itemView);
+            }
+            return animateMove(viewHolder,
+                    preInfo.left, preInfo.top, postInfo.left, postInfo.top);
+        }
+        dispatchMoveFinished(viewHolder);
+        return false;
+    }
+
+    @Override
+    public boolean animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder,
+            @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+        if (DEBUG) {
+            Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView);
+        }
+        final int fromLeft = preInfo.left;
+        final int fromTop = preInfo.top;
+        final int toLeft, toTop;
+        if (newHolder.shouldIgnore()) {
+            toLeft = preInfo.left;
+            toTop = preInfo.top;
+        } else {
+            toLeft = postInfo.left;
+            toTop = postInfo.top;
+        }
+        return animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop);
+    }
+
+    /**
+     * Called when an item is removed from the RecyclerView. Implementors can choose
+     * whether and how to animate that change, but must always call
+     * {@link #dispatchRemoveFinished(ViewHolder)} when done, either
+     * immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * <p>This method may also be called for disappearing items which continue to exist in the
+     * RecyclerView, but for which the system does not have enough information to animate
+     * them out of view. In that case, the default animation for removing items is run
+     * on those items as well.</p>
+     *
+     * @param holder The item that is being removed.
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    public abstract boolean animateRemove(ViewHolder holder);
+
+    /**
+     * Called when an item is added to the RecyclerView. Implementors can choose
+     * whether and how to animate that change, but must always call
+     * {@link #dispatchAddFinished(ViewHolder)} when done, either
+     * immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * <p>This method may also be called for appearing items which were already in the
+     * RecyclerView, but for which the system does not have enough information to animate
+     * them into view. In that case, the default animation for adding items is run
+     * on those items as well.</p>
+     *
+     * @param holder The item that is being added.
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    public abstract boolean animateAdd(ViewHolder holder);
+
+    /**
+     * Called when an item is moved in the RecyclerView. Implementors can choose
+     * whether and how to animate that change, but must always call
+     * {@link #dispatchMoveFinished(ViewHolder)} when done, either
+     * immediately (if no animation will occur) or after the animation actually finishes.
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * @param holder The item that is being moved.
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    public abstract boolean animateMove(ViewHolder holder, int fromX, int fromY,
+            int toX, int toY);
+
+    /**
+     * Called when an item is changed in the RecyclerView, as indicated by a call to
+     * {@link Adapter#notifyItemChanged(int)} or
+     * {@link Adapter#notifyItemRangeChanged(int, int)}.
+     * <p>
+     * Implementers can choose whether and how to animate changes, but must always call
+     * {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null distinct ViewHolder,
+     * either immediately (if no animation will occur) or after the animation actually finishes.
+     * If the {@code oldHolder} is the same ViewHolder as the {@code newHolder}, you must call
+     * {@link #dispatchChangeFinished(ViewHolder, boolean)} once and only once. In that case, the
+     * second parameter of {@code dispatchChangeFinished} is ignored.
+     * <p>
+     * The return value indicates whether an animation has been set up and whether the
+     * ItemAnimator's {@link #runPendingAnimations()} method should be called at the
+     * next opportunity. This mechanism allows ItemAnimator to set up individual animations
+     * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()},
+     * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()},
+     * {@link #animateRemove(ViewHolder) animateRemove()}, and
+     * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one,
+     * then start the animations together in the later call to {@link #runPendingAnimations()}.
+     *
+     * @param oldHolder The original item that changed.
+     * @param newHolder The new item that was created with the changed content. Might be null
+     * @param fromLeft  Left of the old view holder
+     * @param fromTop   Top of the old view holder
+     * @param toLeft    Left of the new view holder
+     * @param toTop     Top of the new view holder
+     * @return true if a later call to {@link #runPendingAnimations()} is requested,
+     * false otherwise.
+     */
+    public abstract boolean animateChange(ViewHolder oldHolder,
+            ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop);
+
+    /**
+     * Method to be called by subclasses when a remove animation is done.
+     *
+     * @param item The item which has been removed
+     * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
+     * ItemHolderInfo)
+     */
+    public final void dispatchRemoveFinished(ViewHolder item) {
+        onRemoveFinished(item);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a move animation is done.
+     *
+     * @param item The item which has been moved
+     * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo,
+     * ItemHolderInfo)
+     * @see RecyclerView.ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     * @see RecyclerView.ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)
+     */
+    public final void dispatchMoveFinished(ViewHolder item) {
+        onMoveFinished(item);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when an add animation is done.
+     *
+     * @param item The item which has been added
+     */
+    public final void dispatchAddFinished(ViewHolder item) {
+        onAddFinished(item);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a change animation is done.
+     *
+     * @param item    The item which has been changed (this method must be called for
+     *                each non-null ViewHolder passed into
+     *                {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     * @see #animateChange(ViewHolder, ViewHolder, int, int, int, int)
+     */
+    public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) {
+        onChangeFinished(item, oldItem);
+        dispatchAnimationFinished(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a remove animation is being started.
+     *
+     * @param item The item being removed
+     */
+    public final void dispatchRemoveStarting(ViewHolder item) {
+        onRemoveStarting(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a move animation is being started.
+     *
+     * @param item The item being moved
+     */
+    public final void dispatchMoveStarting(ViewHolder item) {
+        onMoveStarting(item);
+    }
+
+    /**
+     * Method to be called by subclasses when an add animation is being started.
+     *
+     * @param item The item being added
+     */
+    public final void dispatchAddStarting(ViewHolder item) {
+        onAddStarting(item);
+    }
+
+    /**
+     * Method to be called by subclasses when a change animation is being started.
+     *
+     * @param item    The item which has been changed (this method must be called for
+     *                each non-null ViewHolder passed into
+     *                {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}).
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     */
+    public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) {
+        onChangeStarting(item, oldItem);
+    }
+
+    /**
+     * Called when a remove animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onRemoveStarting(ViewHolder item) {
+    }
+
+    /**
+     * Called when a remove animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    public void onRemoveFinished(ViewHolder item) {
+    }
+
+    /**
+     * Called when an add animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onAddStarting(ViewHolder item) {
+    }
+
+    /**
+     * Called when an add animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    public void onAddFinished(ViewHolder item) {
+    }
+
+    /**
+     * Called when a move animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onMoveStarting(ViewHolder item) {
+    }
+
+    /**
+     * Called when a move animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item The ViewHolder being animated.
+     */
+    public void onMoveFinished(ViewHolder item) {
+    }
+
+    /**
+     * Called when a change animation is being started on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item    The ViewHolder being animated.
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public void onChangeStarting(ViewHolder item, boolean oldItem) {
+    }
+
+    /**
+     * Called when a change animation has ended on the given ViewHolder.
+     * The default implementation does nothing. Subclasses may wish to override
+     * this method to handle any ViewHolder-specific operations linked to animation
+     * lifecycles.
+     *
+     * @param item    The ViewHolder being animated.
+     * @param oldItem true if this is the old item that was changed, false if
+     *                it is the new item that replaced the old item.
+     */
+    public void onChangeFinished(ViewHolder item, boolean oldItem) {
+    }
+}
+
diff --git a/core/java/com/android/internal/widget/ViewInfoStore.java b/core/java/com/android/internal/widget/ViewInfoStore.java
new file mode 100644
index 0000000..6784a85
--- /dev/null
+++ b/core/java/com/android/internal/widget/ViewInfoStore.java
@@ -0,0 +1,330 @@
+/*
+ * 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.widget;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+import android.util.Pools;
+
+import static com.android.internal.widget.RecyclerView.ItemAnimator.ItemHolderInfo;
+import static com.android.internal.widget.RecyclerView.ViewHolder;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_POST;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_PRE;
+import static com.android.internal.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * This class abstracts all tracking for Views to run animations.
+ */
+class ViewInfoStore {
+
+    private static final boolean DEBUG = false;
+
+    /**
+     * View data records for pre-layout
+     */
+    @VisibleForTesting
+    final ArrayMap<ViewHolder, InfoRecord> mLayoutHolderMap = new ArrayMap<>();
+
+    @VisibleForTesting
+    final LongSparseArray<ViewHolder> mOldChangedHolders = new LongSparseArray<>();
+
+    /**
+     * Clears the state and all existing tracking data
+     */
+    void clear() {
+        mLayoutHolderMap.clear();
+        mOldChangedHolders.clear();
+    }
+
+    /**
+     * Adds the item information to the prelayout tracking
+     * @param holder The ViewHolder whose information is being saved
+     * @param info The information to save
+     */
+    void addToPreLayout(ViewHolder holder, ItemHolderInfo info) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.preInfo = info;
+        record.flags |= FLAG_PRE;
+    }
+
+    boolean isDisappearing(ViewHolder holder) {
+        final InfoRecord record = mLayoutHolderMap.get(holder);
+        return record != null && ((record.flags & FLAG_DISAPPEARED) != 0);
+    }
+
+    /**
+     * Finds the ItemHolderInfo for the given ViewHolder in preLayout list and removes it.
+     *
+     * @param vh The ViewHolder whose information is being queried
+     * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
+     */
+    @Nullable
+    ItemHolderInfo popFromPreLayout(ViewHolder vh) {
+        return popFromLayoutStep(vh, FLAG_PRE);
+    }
+
+    /**
+     * Finds the ItemHolderInfo for the given ViewHolder in postLayout list and removes it.
+     *
+     * @param vh The ViewHolder whose information is being queried
+     * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist
+     */
+    @Nullable
+    ItemHolderInfo popFromPostLayout(ViewHolder vh) {
+        return popFromLayoutStep(vh, FLAG_POST);
+    }
+
+    private ItemHolderInfo popFromLayoutStep(ViewHolder vh, int flag) {
+        int index = mLayoutHolderMap.indexOfKey(vh);
+        if (index < 0) {
+            return null;
+        }
+        final InfoRecord record = mLayoutHolderMap.valueAt(index);
+        if (record != null && (record.flags & flag) != 0) {
+            record.flags &= ~flag;
+            final ItemHolderInfo info;
+            if (flag == FLAG_PRE) {
+                info = record.preInfo;
+            } else if (flag == FLAG_POST) {
+                info = record.postInfo;
+            } else {
+                throw new IllegalArgumentException("Must provide flag PRE or POST");
+            }
+            // if not pre-post flag is left, clear.
+            if ((record.flags & (FLAG_PRE | FLAG_POST)) == 0) {
+                mLayoutHolderMap.removeAt(index);
+                InfoRecord.recycle(record);
+            }
+            return info;
+        }
+        return null;
+    }
+
+    /**
+     * Adds the given ViewHolder to the oldChangeHolders list
+     * @param key The key to identify the ViewHolder.
+     * @param holder The ViewHolder to store
+     */
+    void addToOldChangeHolders(long key, ViewHolder holder) {
+        mOldChangedHolders.put(key, holder);
+    }
+
+    /**
+     * Adds the given ViewHolder to the appeared in pre layout list. These are Views added by the
+     * LayoutManager during a pre-layout pass. We distinguish them from other views that were
+     * already in the pre-layout so that ItemAnimator can choose to run a different animation for
+     * them.
+     *
+     * @param holder The ViewHolder to store
+     * @param info The information to save
+     */
+    void addToAppearedInPreLayoutHolders(ViewHolder holder, ItemHolderInfo info) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.flags |= FLAG_APPEAR;
+        record.preInfo = info;
+    }
+
+    /**
+     * Checks whether the given ViewHolder is in preLayout list
+     * @param viewHolder The ViewHolder to query
+     *
+     * @return True if the ViewHolder is present in preLayout, false otherwise
+     */
+    boolean isInPreLayout(ViewHolder viewHolder) {
+        final InfoRecord record = mLayoutHolderMap.get(viewHolder);
+        return record != null && (record.flags & FLAG_PRE) != 0;
+    }
+
+    /**
+     * Queries the oldChangeHolder list for the given key. If they are not tracked, simply returns
+     * null.
+     * @param key The key to be used to find the ViewHolder.
+     *
+     * @return A ViewHolder if exists or null if it does not exist.
+     */
+    ViewHolder getFromOldChangeHolders(long key) {
+        return mOldChangedHolders.get(key);
+    }
+
+    /**
+     * Adds the item information to the post layout list
+     * @param holder The ViewHolder whose information is being saved
+     * @param info The information to save
+     */
+    void addToPostLayout(ViewHolder holder, ItemHolderInfo info) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.postInfo = info;
+        record.flags |= FLAG_POST;
+    }
+
+    /**
+     * A ViewHolder might be added by the LayoutManager just to animate its disappearance.
+     * This list holds such items so that we can animate / recycle these ViewHolders properly.
+     *
+     * @param holder The ViewHolder which disappeared during a layout.
+     */
+    void addToDisappearedInLayout(ViewHolder holder) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            record = InfoRecord.obtain();
+            mLayoutHolderMap.put(holder, record);
+        }
+        record.flags |= FLAG_DISAPPEARED;
+    }
+
+    /**
+     * Removes a ViewHolder from disappearing list.
+     * @param holder The ViewHolder to be removed from the disappearing list.
+     */
+    void removeFromDisappearedInLayout(ViewHolder holder) {
+        InfoRecord record = mLayoutHolderMap.get(holder);
+        if (record == null) {
+            return;
+        }
+        record.flags &= ~FLAG_DISAPPEARED;
+    }
+
+    void process(ProcessCallback callback) {
+        for (int index = mLayoutHolderMap.size() - 1; index >= 0; index--) {
+            final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index);
+            final InfoRecord record = mLayoutHolderMap.removeAt(index);
+            if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) {
+                // Appeared then disappeared. Not useful for animations.
+                callback.unused(viewHolder);
+            } else if ((record.flags & FLAG_DISAPPEARED) != 0) {
+                // Set as "disappeared" by the LayoutManager (addDisappearingView)
+                if (record.preInfo == null) {
+                    // similar to appear disappear but happened between different layout passes.
+                    // this can happen when the layout manager is using auto-measure
+                    callback.unused(viewHolder);
+                } else {
+                    callback.processDisappeared(viewHolder, record.preInfo, record.postInfo);
+                }
+            } else if ((record.flags & FLAG_APPEAR_PRE_AND_POST) == FLAG_APPEAR_PRE_AND_POST) {
+                // Appeared in the layout but not in the adapter (e.g. entered the viewport)
+                callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_PRE_AND_POST) == FLAG_PRE_AND_POST) {
+                // Persistent in both passes. Animate persistence
+                callback.processPersistent(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_PRE) != 0) {
+                // Was in pre-layout, never been added to post layout
+                callback.processDisappeared(viewHolder, record.preInfo, null);
+            } else if ((record.flags & FLAG_POST) != 0) {
+                // Was not in pre-layout, been added to post layout
+                callback.processAppeared(viewHolder, record.preInfo, record.postInfo);
+            } else if ((record.flags & FLAG_APPEAR) != 0) {
+                // Scrap view. RecyclerView will handle removing/recycling this.
+            } else if (DEBUG) {
+                throw new IllegalStateException("record without any reasonable flag combination:/");
+            }
+            InfoRecord.recycle(record);
+        }
+    }
+
+    /**
+     * Removes the ViewHolder from all list
+     * @param holder The ViewHolder which we should stop tracking
+     */
+    void removeViewHolder(ViewHolder holder) {
+        for (int i = mOldChangedHolders.size() - 1; i >= 0; i--) {
+            if (holder == mOldChangedHolders.valueAt(i)) {
+                mOldChangedHolders.removeAt(i);
+                break;
+            }
+        }
+        final InfoRecord info = mLayoutHolderMap.remove(holder);
+        if (info != null) {
+            InfoRecord.recycle(info);
+        }
+    }
+
+    void onDetach() {
+        InfoRecord.drainCache();
+    }
+
+    public void onViewDetached(ViewHolder viewHolder) {
+        removeFromDisappearedInLayout(viewHolder);
+    }
+
+    interface ProcessCallback {
+        void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
+                @Nullable ItemHolderInfo postInfo);
+        void processAppeared(ViewHolder viewHolder, @Nullable ItemHolderInfo preInfo,
+                ItemHolderInfo postInfo);
+        void processPersistent(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo,
+                @NonNull ItemHolderInfo postInfo);
+        void unused(ViewHolder holder);
+    }
+
+    static class InfoRecord {
+        // disappearing list
+        static final int FLAG_DISAPPEARED = 1;
+        // appear in pre layout list
+        static final int FLAG_APPEAR = 1 << 1;
+        // pre layout, this is necessary to distinguish null item info
+        static final int FLAG_PRE = 1 << 2;
+        // post layout, this is necessary to distinguish null item info
+        static final int FLAG_POST = 1 << 3;
+        static final int FLAG_APPEAR_AND_DISAPPEAR = FLAG_APPEAR | FLAG_DISAPPEARED;
+        static final int FLAG_PRE_AND_POST = FLAG_PRE | FLAG_POST;
+        static final int FLAG_APPEAR_PRE_AND_POST = FLAG_APPEAR | FLAG_PRE | FLAG_POST;
+        int flags;
+        @Nullable ItemHolderInfo preInfo;
+        @Nullable ItemHolderInfo postInfo;
+        static Pools.Pool<InfoRecord> sPool = new Pools.SimplePool<>(20);
+
+        private InfoRecord() {
+        }
+
+        static InfoRecord obtain() {
+            InfoRecord record = sPool.acquire();
+            return record == null ? new InfoRecord() : record;
+        }
+
+        static void recycle(InfoRecord record) {
+            record.flags = 0;
+            record.preInfo = null;
+            record.postInfo = null;
+            sPool.release(record);
+        }
+
+        static void drainCache() {
+            //noinspection StatementWithEmptyBody
+            while (sPool.acquire() != null);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/helper/ItemTouchHelper.java b/core/java/com/android/internal/widget/helper/ItemTouchHelper.java
new file mode 100644
index 0000000..9636ed8
--- /dev/null
+++ b/core/java/com/android/internal/widget/helper/ItemTouchHelper.java
@@ -0,0 +1,2391 @@
+/*
+ * 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.widget.helper;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
+import android.view.animation.Interpolator;
+
+import com.android.internal.R;
+import com.android.internal.widget.LinearLayoutManager;
+import com.android.internal.widget.RecyclerView;
+import com.android.internal.widget.RecyclerView.OnItemTouchListener;
+import com.android.internal.widget.RecyclerView.ViewHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.
+ * <p>
+ * It works with a RecyclerView and a Callback class, which configures what type of interactions
+ * are enabled and also receives events when user performs these actions.
+ * <p>
+ * Depending on which functionality you support, you should override
+ * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)} and / or
+ * {@link Callback#onSwiped(ViewHolder, int)}.
+ * <p>
+ * This class is designed to work with any LayoutManager but for certain situations, it can be
+ * optimized for your custom LayoutManager by extending methods in the
+ * {@link ItemTouchHelper.Callback} class or implementing {@link ItemTouchHelper.ViewDropHandler}
+ * interface in your LayoutManager.
+ * <p>
+ * By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. On
+ * platforms older than Honeycomb, ItemTouchHelper uses canvas translations and View's visibility
+ * property to move items in response to touch events. You can customize these behaviors by
+ * overriding {@link Callback#onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int,
+ * boolean)}
+ * or {@link Callback#onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
+ * boolean)}.
+ * <p/>
+ * Most of the time, you only need to override <code>onChildDraw</code> but due to limitations of
+ * platform prior to Honeycomb, you may need to implement <code>onChildDrawOver</code> as well.
+ */
+public class ItemTouchHelper extends RecyclerView.ItemDecoration
+        implements RecyclerView.OnChildAttachStateChangeListener {
+
+    /**
+     * Up direction, used for swipe & drag control.
+     */
+    public static final int UP = 1;
+
+    /**
+     * Down direction, used for swipe & drag control.
+     */
+    public static final int DOWN = 1 << 1;
+
+    /**
+     * Left direction, used for swipe & drag control.
+     */
+    public static final int LEFT = 1 << 2;
+
+    /**
+     * Right direction, used for swipe & drag control.
+     */
+    public static final int RIGHT = 1 << 3;
+
+    // If you change these relative direction values, update Callback#convertToAbsoluteDirection,
+    // Callback#convertToRelativeDirection.
+    /**
+     * Horizontal start direction. Resolved to LEFT or RIGHT depending on RecyclerView's layout
+     * direction. Used for swipe & drag control.
+     */
+    public static final int START = LEFT << 2;
+
+    /**
+     * Horizontal end direction. Resolved to LEFT or RIGHT depending on RecyclerView's layout
+     * direction. Used for swipe & drag control.
+     */
+    public static final int END = RIGHT << 2;
+
+    /**
+     * ItemTouchHelper is in idle state. At this state, either there is no related motion event by
+     * the user or latest motion events have not yet triggered a swipe or drag.
+     */
+    public static final int ACTION_STATE_IDLE = 0;
+
+    /**
+     * A View is currently being swiped.
+     */
+    public static final int ACTION_STATE_SWIPE = 1;
+
+    /**
+     * A View is currently being dragged.
+     */
+    public static final int ACTION_STATE_DRAG = 2;
+
+    /**
+     * Animation type for views which are swiped successfully.
+     */
+    public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 1 << 1;
+
+    /**
+     * Animation type for views which are not completely swiped thus will animate back to their
+     * original position.
+     */
+    public static final int ANIMATION_TYPE_SWIPE_CANCEL = 1 << 2;
+
+    /**
+     * Animation type for views that were dragged and now will animate to their final position.
+     */
+    public static final int ANIMATION_TYPE_DRAG = 1 << 3;
+
+    static final String TAG = "ItemTouchHelper";
+
+    static final boolean DEBUG = false;
+
+    static final int ACTIVE_POINTER_ID_NONE = -1;
+
+    static final int DIRECTION_FLAG_COUNT = 8;
+
+    private static final int ACTION_MODE_IDLE_MASK = (1 << DIRECTION_FLAG_COUNT) - 1;
+
+    static final int ACTION_MODE_SWIPE_MASK = ACTION_MODE_IDLE_MASK << DIRECTION_FLAG_COUNT;
+
+    static final int ACTION_MODE_DRAG_MASK = ACTION_MODE_SWIPE_MASK << DIRECTION_FLAG_COUNT;
+
+    /**
+     * The unit we are using to track velocity
+     */
+    private static final int PIXELS_PER_SECOND = 1000;
+
+    /**
+     * Views, whose state should be cleared after they are detached from RecyclerView.
+     * This is necessary after swipe dismissing an item. We wait until animator finishes its job
+     * to clean these views.
+     */
+    final List<View> mPendingCleanup = new ArrayList<View>();
+
+    /**
+     * Re-use array to calculate dx dy for a ViewHolder
+     */
+    private final float[] mTmpPosition = new float[2];
+
+    /**
+     * Currently selected view holder
+     */
+    ViewHolder mSelected = null;
+
+    /**
+     * The reference coordinates for the action start. For drag & drop, this is the time long
+     * press is completed vs for swipe, this is the initial touch point.
+     */
+    float mInitialTouchX;
+
+    float mInitialTouchY;
+
+    /**
+     * Set when ItemTouchHelper is assigned to a RecyclerView.
+     */
+    float mSwipeEscapeVelocity;
+
+    /**
+     * Set when ItemTouchHelper is assigned to a RecyclerView.
+     */
+    float mMaxSwipeVelocity;
+
+    /**
+     * The diff between the last event and initial touch.
+     */
+    float mDx;
+
+    float mDy;
+
+    /**
+     * The coordinates of the selected view at the time it is selected. We record these values
+     * when action starts so that we can consistently position it even if LayoutManager moves the
+     * View.
+     */
+    float mSelectedStartX;
+
+    float mSelectedStartY;
+
+    /**
+     * The pointer we are tracking.
+     */
+    int mActivePointerId = ACTIVE_POINTER_ID_NONE;
+
+    /**
+     * Developer callback which controls the behavior of ItemTouchHelper.
+     */
+    Callback mCallback;
+
+    /**
+     * Current mode.
+     */
+    int mActionState = ACTION_STATE_IDLE;
+
+    /**
+     * The direction flags obtained from unmasking
+     * {@link Callback#getAbsoluteMovementFlags(RecyclerView, ViewHolder)} for the current
+     * action state.
+     */
+    int mSelectedFlags;
+
+    /**
+     * When a View is dragged or swiped and needs to go back to where it was, we create a Recover
+     * Animation and animate it to its location using this custom Animator, instead of using
+     * framework Animators.
+     * Using framework animators has the side effect of clashing with ItemAnimator, creating
+     * jumpy UIs.
+     */
+    List<RecoverAnimation> mRecoverAnimations = new ArrayList<RecoverAnimation>();
+
+    private int mSlop;
+
+    RecyclerView mRecyclerView;
+
+    /**
+     * When user drags a view to the edge, we start scrolling the LayoutManager as long as View
+     * is partially out of bounds.
+     */
+    final Runnable mScrollRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mSelected != null && scrollIfNecessary()) {
+                if (mSelected != null) { //it might be lost during scrolling
+                    moveIfNecessary(mSelected);
+                }
+                mRecyclerView.removeCallbacks(mScrollRunnable);
+                mRecyclerView.postOnAnimation(this);
+            }
+        }
+    };
+
+    /**
+     * Used for detecting fling swipe
+     */
+    VelocityTracker mVelocityTracker;
+
+    //re-used list for selecting a swap target
+    private List<ViewHolder> mSwapTargets;
+
+    //re used for for sorting swap targets
+    private List<Integer> mDistances;
+
+    /**
+     * If drag & drop is supported, we use child drawing order to bring them to front.
+     */
+    private RecyclerView.ChildDrawingOrderCallback mChildDrawingOrderCallback = null;
+
+    /**
+     * This keeps a reference to the child dragged by the user. Even after user stops dragging,
+     * until view reaches its final position (end of recover animation), we keep a reference so
+     * that it can be drawn above other children.
+     */
+    View mOverdrawChild = null;
+
+    /**
+     * We cache the position of the overdraw child to avoid recalculating it each time child
+     * position callback is called. This value is invalidated whenever a child is attached or
+     * detached.
+     */
+    int mOverdrawChildPosition = -1;
+
+    /**
+     * Used to detect long press.
+     */
+    GestureDetector mGestureDetector;
+
+    private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {
+        @Override
+        public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) {
+            mGestureDetector.onTouchEvent(event);
+            if (DEBUG) {
+                Log.d(TAG, "intercept: x:" + event.getX() + ",y:" + event.getY() + ", " + event);
+            }
+            final int action = event.getActionMasked();
+            if (action == MotionEvent.ACTION_DOWN) {
+                mActivePointerId = event.getPointerId(0);
+                mInitialTouchX = event.getX();
+                mInitialTouchY = event.getY();
+                obtainVelocityTracker();
+                if (mSelected == null) {
+                    final RecoverAnimation animation = findAnimation(event);
+                    if (animation != null) {
+                        mInitialTouchX -= animation.mX;
+                        mInitialTouchY -= animation.mY;
+                        endRecoverAnimation(animation.mViewHolder, true);
+                        if (mPendingCleanup.remove(animation.mViewHolder.itemView)) {
+                            mCallback.clearView(mRecyclerView, animation.mViewHolder);
+                        }
+                        select(animation.mViewHolder, animation.mActionState);
+                        updateDxDy(event, mSelectedFlags, 0);
+                    }
+                }
+            } else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+                mActivePointerId = ACTIVE_POINTER_ID_NONE;
+                select(null, ACTION_STATE_IDLE);
+            } else if (mActivePointerId != ACTIVE_POINTER_ID_NONE) {
+                // in a non scroll orientation, if distance change is above threshold, we
+                // can select the item
+                final int index = event.findPointerIndex(mActivePointerId);
+                if (DEBUG) {
+                    Log.d(TAG, "pointer index " + index);
+                }
+                if (index >= 0) {
+                    checkSelectForSwipe(action, event, index);
+                }
+            }
+            if (mVelocityTracker != null) {
+                mVelocityTracker.addMovement(event);
+            }
+            return mSelected != null;
+        }
+
+        @Override
+        public void onTouchEvent(RecyclerView recyclerView, MotionEvent event) {
+            mGestureDetector.onTouchEvent(event);
+            if (DEBUG) {
+                Log.d(TAG,
+                        "on touch: x:" + mInitialTouchX + ",y:" + mInitialTouchY + ", :" + event);
+            }
+            if (mVelocityTracker != null) {
+                mVelocityTracker.addMovement(event);
+            }
+            if (mActivePointerId == ACTIVE_POINTER_ID_NONE) {
+                return;
+            }
+            final int action = event.getActionMasked();
+            final int activePointerIndex = event.findPointerIndex(mActivePointerId);
+            if (activePointerIndex >= 0) {
+                checkSelectForSwipe(action, event, activePointerIndex);
+            }
+            ViewHolder viewHolder = mSelected;
+            if (viewHolder == null) {
+                return;
+            }
+            switch (action) {
+                case MotionEvent.ACTION_MOVE: {
+                    // Find the index of the active pointer and fetch its position
+                    if (activePointerIndex >= 0) {
+                        updateDxDy(event, mSelectedFlags, activePointerIndex);
+                        moveIfNecessary(viewHolder);
+                        mRecyclerView.removeCallbacks(mScrollRunnable);
+                        mScrollRunnable.run();
+                        mRecyclerView.invalidate();
+                    }
+                    break;
+                }
+                case MotionEvent.ACTION_CANCEL:
+                    if (mVelocityTracker != null) {
+                        mVelocityTracker.clear();
+                    }
+                    // fall through
+                case MotionEvent.ACTION_UP:
+                    select(null, ACTION_STATE_IDLE);
+                    mActivePointerId = ACTIVE_POINTER_ID_NONE;
+                    break;
+                case MotionEvent.ACTION_POINTER_UP: {
+                    final int pointerIndex = event.getActionIndex();
+                    final int pointerId = event.getPointerId(pointerIndex);
+                    if (pointerId == mActivePointerId) {
+                        // This was our active pointer going up. Choose a new
+                        // active pointer and adjust accordingly.
+                        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+                        mActivePointerId = event.getPointerId(newPointerIndex);
+                        updateDxDy(event, mSelectedFlags, pointerIndex);
+                    }
+                    break;
+                }
+            }
+        }
+
+        @Override
+        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+            if (!disallowIntercept) {
+                return;
+            }
+            select(null, ACTION_STATE_IDLE);
+        }
+    };
+
+    /**
+     * Temporary rect instance that is used when we need to lookup Item decorations.
+     */
+    private Rect mTmpRect;
+
+    /**
+     * When user started to drag scroll. Reset when we don't scroll
+     */
+    private long mDragScrollStartTimeInMs;
+
+    /**
+     * Creates an ItemTouchHelper that will work with the given Callback.
+     * <p>
+     * You can attach ItemTouchHelper to a RecyclerView via
+     * {@link #attachToRecyclerView(RecyclerView)}. Upon attaching, it will add an item decoration,
+     * an onItemTouchListener and a Child attach / detach listener to the RecyclerView.
+     *
+     * @param callback The Callback which controls the behavior of this touch helper.
+     */
+    public ItemTouchHelper(Callback callback) {
+        mCallback = callback;
+    }
+
+    private static boolean hitTest(View child, float x, float y, float left, float top) {
+        return x >= left
+                && x <= left + child.getWidth()
+                && y >= top
+                && y <= top + child.getHeight();
+    }
+
+    /**
+     * Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already
+     * attached to a RecyclerView, it will first detach from the previous one. You can call this
+     * method with {@code null} to detach it from the current RecyclerView.
+     *
+     * @param recyclerView The RecyclerView instance to which you want to add this helper or
+     *                     {@code null} if you want to remove ItemTouchHelper from the current
+     *                     RecyclerView.
+     */
+    public void attachToRecyclerView(@Nullable RecyclerView recyclerView) {
+        if (mRecyclerView == recyclerView) {
+            return; // nothing to do
+        }
+        if (mRecyclerView != null) {
+            destroyCallbacks();
+        }
+        mRecyclerView = recyclerView;
+        if (mRecyclerView != null) {
+            final Resources resources = recyclerView.getResources();
+            mSwipeEscapeVelocity = resources
+                    .getDimension(R.dimen.item_touch_helper_swipe_escape_velocity);
+            mMaxSwipeVelocity = resources
+                    .getDimension(R.dimen.item_touch_helper_swipe_escape_max_velocity);
+            setupCallbacks();
+        }
+    }
+
+    private void setupCallbacks() {
+        ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext());
+        mSlop = vc.getScaledTouchSlop();
+        mRecyclerView.addItemDecoration(this);
+        mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
+        mRecyclerView.addOnChildAttachStateChangeListener(this);
+        initGestureDetector();
+    }
+
+    private void destroyCallbacks() {
+        mRecyclerView.removeItemDecoration(this);
+        mRecyclerView.removeOnItemTouchListener(mOnItemTouchListener);
+        mRecyclerView.removeOnChildAttachStateChangeListener(this);
+        // clean all attached
+        final int recoverAnimSize = mRecoverAnimations.size();
+        for (int i = recoverAnimSize - 1; i >= 0; i--) {
+            final RecoverAnimation recoverAnimation = mRecoverAnimations.get(0);
+            mCallback.clearView(mRecyclerView, recoverAnimation.mViewHolder);
+        }
+        mRecoverAnimations.clear();
+        mOverdrawChild = null;
+        mOverdrawChildPosition = -1;
+        releaseVelocityTracker();
+    }
+
+    private void initGestureDetector() {
+        if (mGestureDetector != null) {
+            return;
+        }
+        mGestureDetector = new GestureDetector(mRecyclerView.getContext(),
+                new ItemTouchHelperGestureListener());
+    }
+
+    private void getSelectedDxDy(float[] outPosition) {
+        if ((mSelectedFlags & (LEFT | RIGHT)) != 0) {
+            outPosition[0] = mSelectedStartX + mDx - mSelected.itemView.getLeft();
+        } else {
+            outPosition[0] = mSelected.itemView.getTranslationX();
+        }
+        if ((mSelectedFlags & (UP | DOWN)) != 0) {
+            outPosition[1] = mSelectedStartY + mDy - mSelected.itemView.getTop();
+        } else {
+            outPosition[1] = mSelected.itemView.getTranslationY();
+        }
+    }
+
+    @Override
+    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+        float dx = 0, dy = 0;
+        if (mSelected != null) {
+            getSelectedDxDy(mTmpPosition);
+            dx = mTmpPosition[0];
+            dy = mTmpPosition[1];
+        }
+        mCallback.onDrawOver(c, parent, mSelected,
+                mRecoverAnimations, mActionState, dx, dy);
+    }
+
+    @Override
+    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+        // we don't know if RV changed something so we should invalidate this index.
+        mOverdrawChildPosition = -1;
+        float dx = 0, dy = 0;
+        if (mSelected != null) {
+            getSelectedDxDy(mTmpPosition);
+            dx = mTmpPosition[0];
+            dy = mTmpPosition[1];
+        }
+        mCallback.onDraw(c, parent, mSelected,
+                mRecoverAnimations, mActionState, dx, dy);
+    }
+
+    /**
+     * Starts dragging or swiping the given View. Call with null if you want to clear it.
+     *
+     * @param selected    The ViewHolder to drag or swipe. Can be null if you want to cancel the
+     *                    current action
+     * @param actionState The type of action
+     */
+    void select(ViewHolder selected, int actionState) {
+        if (selected == mSelected && actionState == mActionState) {
+            return;
+        }
+        mDragScrollStartTimeInMs = Long.MIN_VALUE;
+        final int prevActionState = mActionState;
+        // prevent duplicate animations
+        endRecoverAnimation(selected, true);
+        mActionState = actionState;
+        if (actionState == ACTION_STATE_DRAG) {
+            // we remove after animation is complete. this means we only elevate the last drag
+            // child but that should perform good enough as it is very hard to start dragging a
+            // new child before the previous one settles.
+            mOverdrawChild = selected.itemView;
+            addChildDrawingOrderCallback();
+        }
+        int actionStateMask = (1 << (DIRECTION_FLAG_COUNT + DIRECTION_FLAG_COUNT * actionState))
+                - 1;
+        boolean preventLayout = false;
+
+        if (mSelected != null) {
+            final ViewHolder prevSelected = mSelected;
+            if (prevSelected.itemView.getParent() != null) {
+                final int swipeDir = prevActionState == ACTION_STATE_DRAG ? 0
+                        : swipeIfNecessary(prevSelected);
+                releaseVelocityTracker();
+                // find where we should animate to
+                final float targetTranslateX, targetTranslateY;
+                int animationType;
+                switch (swipeDir) {
+                    case LEFT:
+                    case RIGHT:
+                    case START:
+                    case END:
+                        targetTranslateY = 0;
+                        targetTranslateX = Math.signum(mDx) * mRecyclerView.getWidth();
+                        break;
+                    case UP:
+                    case DOWN:
+                        targetTranslateX = 0;
+                        targetTranslateY = Math.signum(mDy) * mRecyclerView.getHeight();
+                        break;
+                    default:
+                        targetTranslateX = 0;
+                        targetTranslateY = 0;
+                }
+                if (prevActionState == ACTION_STATE_DRAG) {
+                    animationType = ANIMATION_TYPE_DRAG;
+                } else if (swipeDir > 0) {
+                    animationType = ANIMATION_TYPE_SWIPE_SUCCESS;
+                } else {
+                    animationType = ANIMATION_TYPE_SWIPE_CANCEL;
+                }
+                getSelectedDxDy(mTmpPosition);
+                final float currentTranslateX = mTmpPosition[0];
+                final float currentTranslateY = mTmpPosition[1];
+                final RecoverAnimation rv = new RecoverAnimation(prevSelected, animationType,
+                        prevActionState, currentTranslateX, currentTranslateY,
+                        targetTranslateX, targetTranslateY) {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        super.onAnimationEnd(animation);
+                        if (this.mOverridden) {
+                            return;
+                        }
+                        if (swipeDir <= 0) {
+                            // this is a drag or failed swipe. recover immediately
+                            mCallback.clearView(mRecyclerView, prevSelected);
+                            // full cleanup will happen on onDrawOver
+                        } else {
+                            // wait until remove animation is complete.
+                            mPendingCleanup.add(prevSelected.itemView);
+                            mIsPendingCleanup = true;
+                            if (swipeDir > 0) {
+                                // Animation might be ended by other animators during a layout.
+                                // We defer callback to avoid editing adapter during a layout.
+                                postDispatchSwipe(this, swipeDir);
+                            }
+                        }
+                        // removed from the list after it is drawn for the last time
+                        if (mOverdrawChild == prevSelected.itemView) {
+                            removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView);
+                        }
+                    }
+                };
+                final long duration = mCallback.getAnimationDuration(mRecyclerView, animationType,
+                        targetTranslateX - currentTranslateX, targetTranslateY - currentTranslateY);
+                rv.setDuration(duration);
+                mRecoverAnimations.add(rv);
+                rv.start();
+                preventLayout = true;
+            } else {
+                removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView);
+                mCallback.clearView(mRecyclerView, prevSelected);
+            }
+            mSelected = null;
+        }
+        if (selected != null) {
+            mSelectedFlags =
+                    (mCallback.getAbsoluteMovementFlags(mRecyclerView, selected) & actionStateMask)
+                            >> (mActionState * DIRECTION_FLAG_COUNT);
+            mSelectedStartX = selected.itemView.getLeft();
+            mSelectedStartY = selected.itemView.getTop();
+            mSelected = selected;
+
+            if (actionState == ACTION_STATE_DRAG) {
+                mSelected.itemView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+            }
+        }
+        final ViewParent rvParent = mRecyclerView.getParent();
+        if (rvParent != null) {
+            rvParent.requestDisallowInterceptTouchEvent(mSelected != null);
+        }
+        if (!preventLayout) {
+            mRecyclerView.getLayoutManager().requestSimpleAnimationsInNextLayout();
+        }
+        mCallback.onSelectedChanged(mSelected, mActionState);
+        mRecyclerView.invalidate();
+    }
+
+    void postDispatchSwipe(final RecoverAnimation anim, final int swipeDir) {
+        // wait until animations are complete.
+        mRecyclerView.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mRecyclerView != null && mRecyclerView.isAttachedToWindow()
+                        && !anim.mOverridden
+                        && anim.mViewHolder.getAdapterPosition() != RecyclerView.NO_POSITION) {
+                    final RecyclerView.ItemAnimator animator = mRecyclerView.getItemAnimator();
+                    // if animator is running or we have other active recover animations, we try
+                    // not to call onSwiped because DefaultItemAnimator is not good at merging
+                    // animations. Instead, we wait and batch.
+                    if ((animator == null || !animator.isRunning(null))
+                            && !hasRunningRecoverAnim()) {
+                        mCallback.onSwiped(anim.mViewHolder, swipeDir);
+                    } else {
+                        mRecyclerView.post(this);
+                    }
+                }
+            }
+        });
+    }
+
+    boolean hasRunningRecoverAnim() {
+        final int size = mRecoverAnimations.size();
+        for (int i = 0; i < size; i++) {
+            if (!mRecoverAnimations.get(i).mEnded) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * If user drags the view to the edge, trigger a scroll if necessary.
+     */
+    boolean scrollIfNecessary() {
+        if (mSelected == null) {
+            mDragScrollStartTimeInMs = Long.MIN_VALUE;
+            return false;
+        }
+        final long now = System.currentTimeMillis();
+        final long scrollDuration = mDragScrollStartTimeInMs
+                == Long.MIN_VALUE ? 0 : now - mDragScrollStartTimeInMs;
+        RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
+        if (mTmpRect == null) {
+            mTmpRect = new Rect();
+        }
+        int scrollX = 0;
+        int scrollY = 0;
+        lm.calculateItemDecorationsForChild(mSelected.itemView, mTmpRect);
+        if (lm.canScrollHorizontally()) {
+            int curX = (int) (mSelectedStartX + mDx);
+            final int leftDiff = curX - mTmpRect.left - mRecyclerView.getPaddingLeft();
+            if (mDx < 0 && leftDiff < 0) {
+                scrollX = leftDiff;
+            } else if (mDx > 0) {
+                final int rightDiff =
+                        curX + mSelected.itemView.getWidth() + mTmpRect.right
+                                - (mRecyclerView.getWidth() - mRecyclerView.getPaddingRight());
+                if (rightDiff > 0) {
+                    scrollX = rightDiff;
+                }
+            }
+        }
+        if (lm.canScrollVertically()) {
+            int curY = (int) (mSelectedStartY + mDy);
+            final int topDiff = curY - mTmpRect.top - mRecyclerView.getPaddingTop();
+            if (mDy < 0 && topDiff < 0) {
+                scrollY = topDiff;
+            } else if (mDy > 0) {
+                final int bottomDiff = curY + mSelected.itemView.getHeight() + mTmpRect.bottom
+                        - (mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom());
+                if (bottomDiff > 0) {
+                    scrollY = bottomDiff;
+                }
+            }
+        }
+        if (scrollX != 0) {
+            scrollX = mCallback.interpolateOutOfBoundsScroll(mRecyclerView,
+                    mSelected.itemView.getWidth(), scrollX,
+                    mRecyclerView.getWidth(), scrollDuration);
+        }
+        if (scrollY != 0) {
+            scrollY = mCallback.interpolateOutOfBoundsScroll(mRecyclerView,
+                    mSelected.itemView.getHeight(), scrollY,
+                    mRecyclerView.getHeight(), scrollDuration);
+        }
+        if (scrollX != 0 || scrollY != 0) {
+            if (mDragScrollStartTimeInMs == Long.MIN_VALUE) {
+                mDragScrollStartTimeInMs = now;
+            }
+            mRecyclerView.scrollBy(scrollX, scrollY);
+            return true;
+        }
+        mDragScrollStartTimeInMs = Long.MIN_VALUE;
+        return false;
+    }
+
+    private List<ViewHolder> findSwapTargets(ViewHolder viewHolder) {
+        if (mSwapTargets == null) {
+            mSwapTargets = new ArrayList<ViewHolder>();
+            mDistances = new ArrayList<Integer>();
+        } else {
+            mSwapTargets.clear();
+            mDistances.clear();
+        }
+        final int margin = mCallback.getBoundingBoxMargin();
+        final int left = Math.round(mSelectedStartX + mDx) - margin;
+        final int top = Math.round(mSelectedStartY + mDy) - margin;
+        final int right = left + viewHolder.itemView.getWidth() + 2 * margin;
+        final int bottom = top + viewHolder.itemView.getHeight() + 2 * margin;
+        final int centerX = (left + right) / 2;
+        final int centerY = (top + bottom) / 2;
+        final RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
+        final int childCount = lm.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View other = lm.getChildAt(i);
+            if (other == viewHolder.itemView) {
+                continue; //myself!
+            }
+            if (other.getBottom() < top || other.getTop() > bottom
+                    || other.getRight() < left || other.getLeft() > right) {
+                continue;
+            }
+            final ViewHolder otherVh = mRecyclerView.getChildViewHolder(other);
+            if (mCallback.canDropOver(mRecyclerView, mSelected, otherVh)) {
+                // find the index to add
+                final int dx = Math.abs(centerX - (other.getLeft() + other.getRight()) / 2);
+                final int dy = Math.abs(centerY - (other.getTop() + other.getBottom()) / 2);
+                final int dist = dx * dx + dy * dy;
+
+                int pos = 0;
+                final int cnt = mSwapTargets.size();
+                for (int j = 0; j < cnt; j++) {
+                    if (dist > mDistances.get(j)) {
+                        pos++;
+                    } else {
+                        break;
+                    }
+                }
+                mSwapTargets.add(pos, otherVh);
+                mDistances.add(pos, dist);
+            }
+        }
+        return mSwapTargets;
+    }
+
+    /**
+     * Checks if we should swap w/ another view holder.
+     */
+    void moveIfNecessary(ViewHolder viewHolder) {
+        if (mRecyclerView.isLayoutRequested()) {
+            return;
+        }
+        if (mActionState != ACTION_STATE_DRAG) {
+            return;
+        }
+
+        final float threshold = mCallback.getMoveThreshold(viewHolder);
+        final int x = (int) (mSelectedStartX + mDx);
+        final int y = (int) (mSelectedStartY + mDy);
+        if (Math.abs(y - viewHolder.itemView.getTop()) < viewHolder.itemView.getHeight() * threshold
+                && Math.abs(x - viewHolder.itemView.getLeft())
+                < viewHolder.itemView.getWidth() * threshold) {
+            return;
+        }
+        List<ViewHolder> swapTargets = findSwapTargets(viewHolder);
+        if (swapTargets.size() == 0) {
+            return;
+        }
+        // may swap.
+        ViewHolder target = mCallback.chooseDropTarget(viewHolder, swapTargets, x, y);
+        if (target == null) {
+            mSwapTargets.clear();
+            mDistances.clear();
+            return;
+        }
+        final int toPosition = target.getAdapterPosition();
+        final int fromPosition = viewHolder.getAdapterPosition();
+        if (mCallback.onMove(mRecyclerView, viewHolder, target)) {
+            // keep target visible
+            mCallback.onMoved(mRecyclerView, viewHolder, fromPosition,
+                    target, toPosition, x, y);
+        }
+    }
+
+    @Override
+    public void onChildViewAttachedToWindow(View view) {
+    }
+
+    @Override
+    public void onChildViewDetachedFromWindow(View view) {
+        removeChildDrawingOrderCallbackIfNecessary(view);
+        final ViewHolder holder = mRecyclerView.getChildViewHolder(view);
+        if (holder == null) {
+            return;
+        }
+        if (mSelected != null && holder == mSelected) {
+            select(null, ACTION_STATE_IDLE);
+        } else {
+            endRecoverAnimation(holder, false); // this may push it into pending cleanup list.
+            if (mPendingCleanup.remove(holder.itemView)) {
+                mCallback.clearView(mRecyclerView, holder);
+            }
+        }
+    }
+
+    /**
+     * Returns the animation type or 0 if cannot be found.
+     */
+    int endRecoverAnimation(ViewHolder viewHolder, boolean override) {
+        final int recoverAnimSize = mRecoverAnimations.size();
+        for (int i = recoverAnimSize - 1; i >= 0; i--) {
+            final RecoverAnimation anim = mRecoverAnimations.get(i);
+            if (anim.mViewHolder == viewHolder) {
+                anim.mOverridden |= override;
+                if (!anim.mEnded) {
+                    anim.cancel();
+                }
+                mRecoverAnimations.remove(i);
+                return anim.mAnimationType;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+            RecyclerView.State state) {
+        outRect.setEmpty();
+    }
+
+    void obtainVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    private void releaseVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+            mVelocityTracker = null;
+        }
+    }
+
+    private ViewHolder findSwipedView(MotionEvent motionEvent) {
+        final RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
+        if (mActivePointerId == ACTIVE_POINTER_ID_NONE) {
+            return null;
+        }
+        final int pointerIndex = motionEvent.findPointerIndex(mActivePointerId);
+        final float dx = motionEvent.getX(pointerIndex) - mInitialTouchX;
+        final float dy = motionEvent.getY(pointerIndex) - mInitialTouchY;
+        final float absDx = Math.abs(dx);
+        final float absDy = Math.abs(dy);
+
+        if (absDx < mSlop && absDy < mSlop) {
+            return null;
+        }
+        if (absDx > absDy && lm.canScrollHorizontally()) {
+            return null;
+        } else if (absDy > absDx && lm.canScrollVertically()) {
+            return null;
+        }
+        View child = findChildView(motionEvent);
+        if (child == null) {
+            return null;
+        }
+        return mRecyclerView.getChildViewHolder(child);
+    }
+
+    /**
+     * Checks whether we should select a View for swiping.
+     */
+    boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
+        if (mSelected != null || action != MotionEvent.ACTION_MOVE
+                || mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) {
+            return false;
+        }
+        if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
+            return false;
+        }
+        final ViewHolder vh = findSwipedView(motionEvent);
+        if (vh == null) {
+            return false;
+        }
+        final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh);
+
+        final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK)
+                >> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
+
+        if (swipeFlags == 0) {
+            return false;
+        }
+
+        // mDx and mDy are only set in allowed directions. We use custom x/y here instead of
+        // updateDxDy to avoid swiping if user moves more in the other direction
+        final float x = motionEvent.getX(pointerIndex);
+        final float y = motionEvent.getY(pointerIndex);
+
+        // Calculate the distance moved
+        final float dx = x - mInitialTouchX;
+        final float dy = y - mInitialTouchY;
+        // swipe target is chose w/o applying flags so it does not really check if swiping in that
+        // direction is allowed. This why here, we use mDx mDy to check slope value again.
+        final float absDx = Math.abs(dx);
+        final float absDy = Math.abs(dy);
+
+        if (absDx < mSlop && absDy < mSlop) {
+            return false;
+        }
+        if (absDx > absDy) {
+            if (dx < 0 && (swipeFlags & LEFT) == 0) {
+                return false;
+            }
+            if (dx > 0 && (swipeFlags & RIGHT) == 0) {
+                return false;
+            }
+        } else {
+            if (dy < 0 && (swipeFlags & UP) == 0) {
+                return false;
+            }
+            if (dy > 0 && (swipeFlags & DOWN) == 0) {
+                return false;
+            }
+        }
+        mDx = mDy = 0f;
+        mActivePointerId = motionEvent.getPointerId(0);
+        select(vh, ACTION_STATE_SWIPE);
+        return true;
+    }
+
+    View findChildView(MotionEvent event) {
+        // first check elevated views, if none, then call RV
+        final float x = event.getX();
+        final float y = event.getY();
+        if (mSelected != null) {
+            final View selectedView = mSelected.itemView;
+            if (hitTest(selectedView, x, y, mSelectedStartX + mDx, mSelectedStartY + mDy)) {
+                return selectedView;
+            }
+        }
+        for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {
+            final RecoverAnimation anim = mRecoverAnimations.get(i);
+            final View view = anim.mViewHolder.itemView;
+            if (hitTest(view, x, y, anim.mX, anim.mY)) {
+                return view;
+            }
+        }
+        return mRecyclerView.findChildViewUnder(x, y);
+    }
+
+    /**
+     * Starts dragging the provided ViewHolder. By default, ItemTouchHelper starts a drag when a
+     * View is long pressed. You can disable that behavior by overriding
+     * {@link ItemTouchHelper.Callback#isLongPressDragEnabled()}.
+     * <p>
+     * For this method to work:
+     * <ul>
+     * <li>The provided ViewHolder must be a child of the RecyclerView to which this
+     * ItemTouchHelper
+     * is attached.</li>
+     * <li>{@link ItemTouchHelper.Callback} must have dragging enabled.</li>
+     * <li>There must be a previous touch event that was reported to the ItemTouchHelper
+     * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener
+     * grabs previous events, this should work as expected.</li>
+     * </ul>
+     *
+     * For example, if you would like to let your user to be able to drag an Item by touching one
+     * of its descendants, you may implement it as follows:
+     * <pre>
+     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
+     *         public boolean onTouch(View v, MotionEvent event) {
+     *             if (MotionEvent.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+     *                 mItemTouchHelper.startDrag(viewHolder);
+     *             }
+     *             return false;
+     *         }
+     *     });
+     * </pre>
+     * <p>
+     *
+     * @param viewHolder The ViewHolder to start dragging. It must be a direct child of
+     *                   RecyclerView.
+     * @see ItemTouchHelper.Callback#isItemViewSwipeEnabled()
+     */
+    public void startDrag(ViewHolder viewHolder) {
+        if (!mCallback.hasDragFlag(mRecyclerView, viewHolder)) {
+            Log.e(TAG, "Start drag has been called but dragging is not enabled");
+            return;
+        }
+        if (viewHolder.itemView.getParent() != mRecyclerView) {
+            Log.e(TAG, "Start drag has been called with a view holder which is not a child of "
+                    + "the RecyclerView which is controlled by this ItemTouchHelper.");
+            return;
+        }
+        obtainVelocityTracker();
+        mDx = mDy = 0f;
+        select(viewHolder, ACTION_STATE_DRAG);
+    }
+
+    /**
+     * Starts swiping the provided ViewHolder. By default, ItemTouchHelper starts swiping a View
+     * when user swipes their finger (or mouse pointer) over the View. You can disable this
+     * behavior
+     * by overriding {@link ItemTouchHelper.Callback}
+     * <p>
+     * For this method to work:
+     * <ul>
+     * <li>The provided ViewHolder must be a child of the RecyclerView to which this
+     * ItemTouchHelper is attached.</li>
+     * <li>{@link ItemTouchHelper.Callback} must have swiping enabled.</li>
+     * <li>There must be a previous touch event that was reported to the ItemTouchHelper
+     * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener
+     * grabs previous events, this should work as expected.</li>
+     * </ul>
+     *
+     * For example, if you would like to let your user to be able to swipe an Item by touching one
+     * of its descendants, you may implement it as follows:
+     * <pre>
+     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
+     *         public boolean onTouch(View v, MotionEvent event) {
+     *             if (MotionEvent.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+     *                 mItemTouchHelper.startSwipe(viewHolder);
+     *             }
+     *             return false;
+     *         }
+     *     });
+     * </pre>
+     *
+     * @param viewHolder The ViewHolder to start swiping. It must be a direct child of
+     *                   RecyclerView.
+     */
+    public void startSwipe(ViewHolder viewHolder) {
+        if (!mCallback.hasSwipeFlag(mRecyclerView, viewHolder)) {
+            Log.e(TAG, "Start swipe has been called but swiping is not enabled");
+            return;
+        }
+        if (viewHolder.itemView.getParent() != mRecyclerView) {
+            Log.e(TAG, "Start swipe has been called with a view holder which is not a child of "
+                    + "the RecyclerView controlled by this ItemTouchHelper.");
+            return;
+        }
+        obtainVelocityTracker();
+        mDx = mDy = 0f;
+        select(viewHolder, ACTION_STATE_SWIPE);
+    }
+
+    RecoverAnimation findAnimation(MotionEvent event) {
+        if (mRecoverAnimations.isEmpty()) {
+            return null;
+        }
+        View target = findChildView(event);
+        for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) {
+            final RecoverAnimation anim = mRecoverAnimations.get(i);
+            if (anim.mViewHolder.itemView == target) {
+                return anim;
+            }
+        }
+        return null;
+    }
+
+    void updateDxDy(MotionEvent ev, int directionFlags, int pointerIndex) {
+        final float x = ev.getX(pointerIndex);
+        final float y = ev.getY(pointerIndex);
+
+        // Calculate the distance moved
+        mDx = x - mInitialTouchX;
+        mDy = y - mInitialTouchY;
+        if ((directionFlags & LEFT) == 0) {
+            mDx = Math.max(0, mDx);
+        }
+        if ((directionFlags & RIGHT) == 0) {
+            mDx = Math.min(0, mDx);
+        }
+        if ((directionFlags & UP) == 0) {
+            mDy = Math.max(0, mDy);
+        }
+        if ((directionFlags & DOWN) == 0) {
+            mDy = Math.min(0, mDy);
+        }
+    }
+
+    private int swipeIfNecessary(ViewHolder viewHolder) {
+        if (mActionState == ACTION_STATE_DRAG) {
+            return 0;
+        }
+        final int originalMovementFlags = mCallback.getMovementFlags(mRecyclerView, viewHolder);
+        final int absoluteMovementFlags = mCallback.convertToAbsoluteDirection(
+                originalMovementFlags,
+                mRecyclerView.getLayoutDirection());
+        final int flags = (absoluteMovementFlags
+                & ACTION_MODE_SWIPE_MASK) >> (ACTION_STATE_SWIPE * DIRECTION_FLAG_COUNT);
+        if (flags == 0) {
+            return 0;
+        }
+        final int originalFlags = (originalMovementFlags
+                & ACTION_MODE_SWIPE_MASK) >> (ACTION_STATE_SWIPE * DIRECTION_FLAG_COUNT);
+        int swipeDir;
+        if (Math.abs(mDx) > Math.abs(mDy)) {
+            if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) {
+                // if swipe dir is not in original flags, it should be the relative direction
+                if ((originalFlags & swipeDir) == 0) {
+                    // convert to relative
+                    return Callback.convertToRelativeDirection(swipeDir,
+                            mRecyclerView.getLayoutDirection());
+                }
+                return swipeDir;
+            }
+            if ((swipeDir = checkVerticalSwipe(viewHolder, flags)) > 0) {
+                return swipeDir;
+            }
+        } else {
+            if ((swipeDir = checkVerticalSwipe(viewHolder, flags)) > 0) {
+                return swipeDir;
+            }
+            if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) {
+                // if swipe dir is not in original flags, it should be the relative direction
+                if ((originalFlags & swipeDir) == 0) {
+                    // convert to relative
+                    return Callback.convertToRelativeDirection(swipeDir,
+                            mRecyclerView.getLayoutDirection());
+                }
+                return swipeDir;
+            }
+        }
+        return 0;
+    }
+
+    private int checkHorizontalSwipe(ViewHolder viewHolder, int flags) {
+        if ((flags & (LEFT | RIGHT)) != 0) {
+            final int dirFlag = mDx > 0 ? RIGHT : LEFT;
+            if (mVelocityTracker != null && mActivePointerId > -1) {
+                mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
+                        mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
+                final float xVelocity = mVelocityTracker.getXVelocity(mActivePointerId);
+                final float yVelocity = mVelocityTracker.getYVelocity(mActivePointerId);
+                final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT;
+                final float absXVelocity = Math.abs(xVelocity);
+                if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag
+                        && absXVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity)
+                        && absXVelocity > Math.abs(yVelocity)) {
+                    return velDirFlag;
+                }
+            }
+
+            final float threshold = mRecyclerView.getWidth() * mCallback
+                    .getSwipeThreshold(viewHolder);
+
+            if ((flags & dirFlag) != 0 && Math.abs(mDx) > threshold) {
+                return dirFlag;
+            }
+        }
+        return 0;
+    }
+
+    private int checkVerticalSwipe(ViewHolder viewHolder, int flags) {
+        if ((flags & (UP | DOWN)) != 0) {
+            final int dirFlag = mDy > 0 ? DOWN : UP;
+            if (mVelocityTracker != null && mActivePointerId > -1) {
+                mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND,
+                        mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity));
+                final float xVelocity = mVelocityTracker.getXVelocity(mActivePointerId);
+                final float yVelocity = mVelocityTracker.getYVelocity(mActivePointerId);
+                final int velDirFlag = yVelocity > 0f ? DOWN : UP;
+                final float absYVelocity = Math.abs(yVelocity);
+                if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag
+                        && absYVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity)
+                        && absYVelocity > Math.abs(xVelocity)) {
+                    return velDirFlag;
+                }
+            }
+
+            final float threshold = mRecyclerView.getHeight() * mCallback
+                    .getSwipeThreshold(viewHolder);
+            if ((flags & dirFlag) != 0 && Math.abs(mDy) > threshold) {
+                return dirFlag;
+            }
+        }
+        return 0;
+    }
+
+    private void addChildDrawingOrderCallback() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return; // we use elevation on Lollipop
+        }
+        if (mChildDrawingOrderCallback == null) {
+            mChildDrawingOrderCallback = new RecyclerView.ChildDrawingOrderCallback() {
+                @Override
+                public int onGetChildDrawingOrder(int childCount, int i) {
+                    if (mOverdrawChild == null) {
+                        return i;
+                    }
+                    int childPosition = mOverdrawChildPosition;
+                    if (childPosition == -1) {
+                        childPosition = mRecyclerView.indexOfChild(mOverdrawChild);
+                        mOverdrawChildPosition = childPosition;
+                    }
+                    if (i == childCount - 1) {
+                        return childPosition;
+                    }
+                    return i < childPosition ? i : i + 1;
+                }
+            };
+        }
+        mRecyclerView.setChildDrawingOrderCallback(mChildDrawingOrderCallback);
+    }
+
+    void removeChildDrawingOrderCallbackIfNecessary(View view) {
+        if (view == mOverdrawChild) {
+            mOverdrawChild = null;
+            // only remove if we've added
+            if (mChildDrawingOrderCallback != null) {
+                mRecyclerView.setChildDrawingOrderCallback(null);
+            }
+        }
+    }
+
+    /**
+     * An interface which can be implemented by LayoutManager for better integration with
+     * {@link ItemTouchHelper}.
+     */
+    public interface ViewDropHandler {
+
+        /**
+         * Called by the {@link ItemTouchHelper} after a View is dropped over another View.
+         * <p>
+         * A LayoutManager should implement this interface to get ready for the upcoming move
+         * operation.
+         * <p>
+         * For example, LinearLayoutManager sets up a "scrollToPositionWithOffset" calls so that
+         * the View under drag will be used as an anchor View while calculating the next layout,
+         * making layout stay consistent.
+         *
+         * @param view   The View which is being dragged. It is very likely that user is still
+         *               dragging this View so there might be other
+         *               {@link #prepareForDrop(View, View, int, int)} after this one.
+         * @param target The target view which is being dropped on.
+         * @param x      The <code>left</code> offset of the View that is being dragged. This value
+         *               includes the movement caused by the user.
+         * @param y      The <code>top</code> offset of the View that is being dragged. This value
+         *               includes the movement caused by the user.
+         */
+        void prepareForDrop(View view, View target, int x, int y);
+    }
+
+    /**
+     * This class is the contract between ItemTouchHelper and your application. It lets you control
+     * which touch behaviors are enabled per each ViewHolder and also receive callbacks when user
+     * performs these actions.
+     * <p>
+     * To control which actions user can take on each view, you should override
+     * {@link #getMovementFlags(RecyclerView, ViewHolder)} and return appropriate set
+     * of direction flags. ({@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link #END},
+     * {@link #UP}, {@link #DOWN}). You can use
+     * {@link #makeMovementFlags(int, int)} to easily construct it. Alternatively, you can use
+     * {@link SimpleCallback}.
+     * <p>
+     * If user drags an item, ItemTouchHelper will call
+     * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)
+     * onMove(recyclerView, dragged, target)}.
+     * Upon receiving this callback, you should move the item from the old position
+     * ({@code dragged.getAdapterPosition()}) to new position ({@code target.getAdapterPosition()})
+     * in your adapter and also call {@link RecyclerView.Adapter#notifyItemMoved(int, int)}.
+     * To control where a View can be dropped, you can override
+     * {@link #canDropOver(RecyclerView, ViewHolder, ViewHolder)}. When a
+     * dragging View overlaps multiple other views, Callback chooses the closest View with which
+     * dragged View might have changed positions. Although this approach works for many use cases,
+     * if you have a custom LayoutManager, you can override
+     * {@link #chooseDropTarget(ViewHolder, java.util.List, int, int)} to select a
+     * custom drop target.
+     * <p>
+     * When a View is swiped, ItemTouchHelper animates it until it goes out of bounds, then calls
+     * {@link #onSwiped(ViewHolder, int)}. At this point, you should update your
+     * adapter (e.g. remove the item) and call related Adapter#notify event.
+     */
+    @SuppressWarnings("UnusedParameters")
+    public abstract static class Callback {
+
+        public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200;
+
+        public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250;
+
+        static final int RELATIVE_DIR_FLAGS = START | END
+                | ((START | END) << DIRECTION_FLAG_COUNT)
+                | ((START | END) << (2 * DIRECTION_FLAG_COUNT));
+
+        private static final ItemTouchUIUtil sUICallback = new ItemTouchUIUtilImpl();
+
+        private static final int ABS_HORIZONTAL_DIR_FLAGS = LEFT | RIGHT
+                | ((LEFT | RIGHT) << DIRECTION_FLAG_COUNT)
+                | ((LEFT | RIGHT) << (2 * DIRECTION_FLAG_COUNT));
+
+        private static final Interpolator sDragScrollInterpolator = new Interpolator() {
+            @Override
+            public float getInterpolation(float t) {
+                return t * t * t * t * t;
+            }
+        };
+
+        private static final Interpolator sDragViewScrollCapInterpolator = new Interpolator() {
+            @Override
+            public float getInterpolation(float t) {
+                t -= 1.0f;
+                return t * t * t * t * t + 1.0f;
+            }
+        };
+
+        /**
+         * Drag scroll speed keeps accelerating until this many milliseconds before being capped.
+         */
+        private static final long DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
+
+        private int mCachedMaxScrollSpeed = -1;
+
+        /**
+         * Returns the {@link ItemTouchUIUtil} that is used by the {@link Callback} class for
+         * visual
+         * changes on Views in response to user interactions. {@link ItemTouchUIUtil} has different
+         * implementations for different platform versions.
+         * <p>
+         * By default, {@link Callback} applies these changes on
+         * {@link RecyclerView.ViewHolder#itemView}.
+         * <p>
+         * For example, if you have a use case where you only want the text to move when user
+         * swipes over the view, you can do the following:
+         * <pre>
+         *     public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder){
+         *         getDefaultUIUtil().clearView(((ItemTouchViewHolder) viewHolder).textView);
+         *     }
+         *     public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+         *         if (viewHolder != null){
+         *             getDefaultUIUtil().onSelected(((ItemTouchViewHolder) viewHolder).textView);
+         *         }
+         *     }
+         *     public void onChildDraw(Canvas c, RecyclerView recyclerView,
+         *             RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+         *             boolean isCurrentlyActive) {
+         *         getDefaultUIUtil().onDraw(c, recyclerView,
+         *                 ((ItemTouchViewHolder) viewHolder).textView, dX, dY,
+         *                 actionState, isCurrentlyActive);
+         *         return true;
+         *     }
+         *     public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
+         *             RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+         *             boolean isCurrentlyActive) {
+         *         getDefaultUIUtil().onDrawOver(c, recyclerView,
+         *                 ((ItemTouchViewHolder) viewHolder).textView, dX, dY,
+         *                 actionState, isCurrentlyActive);
+         *         return true;
+         *     }
+         * </pre>
+         *
+         * @return The {@link ItemTouchUIUtil} instance that is used by the {@link Callback}
+         */
+        public static ItemTouchUIUtil getDefaultUIUtil() {
+            return sUICallback;
+        }
+
+        /**
+         * Replaces a movement direction with its relative version by taking layout direction into
+         * account.
+         *
+         * @param flags           The flag value that include any number of movement flags.
+         * @param layoutDirection The layout direction of the View. Can be obtained from
+         *                        {@link View#getLayoutDirection()}.
+         * @return Updated flags which uses relative flags ({@link #START}, {@link #END}) instead
+         * of {@link #LEFT}, {@link #RIGHT}.
+         * @see #convertToAbsoluteDirection(int, int)
+         */
+        public static int convertToRelativeDirection(int flags, int layoutDirection) {
+            int masked = flags & ABS_HORIZONTAL_DIR_FLAGS;
+            if (masked == 0) {
+                return flags; // does not have any abs flags, good.
+            }
+            flags &= ~masked; //remove left / right.
+            if (layoutDirection == View.LAYOUT_DIRECTION_LTR) {
+                // no change. just OR with 2 bits shifted mask and return
+                flags |= masked << 2; // START is 2 bits after LEFT, END is 2 bits after RIGHT.
+                return flags;
+            } else {
+                // add RIGHT flag as START
+                flags |= ((masked << 1) & ~ABS_HORIZONTAL_DIR_FLAGS);
+                // first clean RIGHT bit then add LEFT flag as END
+                flags |= ((masked << 1) & ABS_HORIZONTAL_DIR_FLAGS) << 2;
+            }
+            return flags;
+        }
+
+        /**
+         * Convenience method to create movement flags.
+         * <p>
+         * For instance, if you want to let your items be drag & dropped vertically and swiped
+         * left to be dismissed, you can call this method with:
+         * <code>makeMovementFlags(UP | DOWN, LEFT);</code>
+         *
+         * @param dragFlags  The directions in which the item can be dragged.
+         * @param swipeFlags The directions in which the item can be swiped.
+         * @return Returns an integer composed of the given drag and swipe flags.
+         */
+        public static int makeMovementFlags(int dragFlags, int swipeFlags) {
+            return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags)
+                    | makeFlag(ACTION_STATE_SWIPE, swipeFlags)
+                    | makeFlag(ACTION_STATE_DRAG, dragFlags);
+        }
+
+        /**
+         * Shifts the given direction flags to the offset of the given action state.
+         *
+         * @param actionState The action state you want to get flags in. Should be one of
+         *                    {@link #ACTION_STATE_IDLE}, {@link #ACTION_STATE_SWIPE} or
+         *                    {@link #ACTION_STATE_DRAG}.
+         * @param directions  The direction flags. Can be composed from {@link #UP}, {@link #DOWN},
+         *                    {@link #RIGHT}, {@link #LEFT} {@link #START} and {@link #END}.
+         * @return And integer that represents the given directions in the provided actionState.
+         */
+        public static int makeFlag(int actionState, int directions) {
+            return directions << (actionState * DIRECTION_FLAG_COUNT);
+        }
+
+        /**
+         * Should return a composite flag which defines the enabled move directions in each state
+         * (idle, swiping, dragging).
+         * <p>
+         * Instead of composing this flag manually, you can use {@link #makeMovementFlags(int,
+         * int)}
+         * or {@link #makeFlag(int, int)}.
+         * <p>
+         * This flag is composed of 3 sets of 8 bits, where first 8 bits are for IDLE state, next
+         * 8 bits are for SWIPE state and third 8 bits are for DRAG state.
+         * Each 8 bit sections can be constructed by simply OR'ing direction flags defined in
+         * {@link ItemTouchHelper}.
+         * <p>
+         * For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to
+         * swipe by swiping RIGHT, you can return:
+         * <pre>
+         *      makeFlag(ACTION_STATE_IDLE, RIGHT) | makeFlag(ACTION_STATE_SWIPE, LEFT | RIGHT);
+         * </pre>
+         * This means, allow right movement while IDLE and allow right and left movement while
+         * swiping.
+         *
+         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached.
+         * @param viewHolder   The ViewHolder for which the movement information is necessary.
+         * @return flags specifying which movements are allowed on this ViewHolder.
+         * @see #makeMovementFlags(int, int)
+         * @see #makeFlag(int, int)
+         */
+        public abstract int getMovementFlags(RecyclerView recyclerView,
+                ViewHolder viewHolder);
+
+        /**
+         * Converts a given set of flags to absolution direction which means {@link #START} and
+         * {@link #END} are replaced with {@link #LEFT} and {@link #RIGHT} depending on the layout
+         * direction.
+         *
+         * @param flags           The flag value that include any number of movement flags.
+         * @param layoutDirection The layout direction of the RecyclerView.
+         * @return Updated flags which includes only absolute direction values.
+         */
+        public int convertToAbsoluteDirection(int flags, int layoutDirection) {
+            int masked = flags & RELATIVE_DIR_FLAGS;
+            if (masked == 0) {
+                return flags; // does not have any relative flags, good.
+            }
+            flags &= ~masked; //remove start / end
+            if (layoutDirection == View.LAYOUT_DIRECTION_LTR) {
+                // no change. just OR with 2 bits shifted mask and return
+                flags |= masked >> 2; // START is 2 bits after LEFT, END is 2 bits after RIGHT.
+                return flags;
+            } else {
+                // add START flag as RIGHT
+                flags |= ((masked >> 1) & ~RELATIVE_DIR_FLAGS);
+                // first clean start bit then add END flag as LEFT
+                flags |= ((masked >> 1) & RELATIVE_DIR_FLAGS) >> 2;
+            }
+            return flags;
+        }
+
+        final int getAbsoluteMovementFlags(RecyclerView recyclerView,
+                ViewHolder viewHolder) {
+            final int flags = getMovementFlags(recyclerView, viewHolder);
+            return convertToAbsoluteDirection(flags, recyclerView.getLayoutDirection());
+        }
+
+        boolean hasDragFlag(RecyclerView recyclerView, ViewHolder viewHolder) {
+            final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder);
+            return (flags & ACTION_MODE_DRAG_MASK) != 0;
+        }
+
+        boolean hasSwipeFlag(RecyclerView recyclerView,
+                ViewHolder viewHolder) {
+            final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder);
+            return (flags & ACTION_MODE_SWIPE_MASK) != 0;
+        }
+
+        /**
+         * Return true if the current ViewHolder can be dropped over the the target ViewHolder.
+         * <p>
+         * This method is used when selecting drop target for the dragged View. After Views are
+         * eliminated either via bounds check or via this method, resulting set of views will be
+         * passed to {@link #chooseDropTarget(ViewHolder, java.util.List, int, int)}.
+         * <p>
+         * Default implementation returns true.
+         *
+         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to.
+         * @param current      The ViewHolder that user is dragging.
+         * @param target       The ViewHolder which is below the dragged ViewHolder.
+         * @return True if the dragged ViewHolder can be replaced with the target ViewHolder, false
+         * otherwise.
+         */
+        public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
+                ViewHolder target) {
+            return true;
+        }
+
+        /**
+         * Called when ItemTouchHelper wants to move the dragged item from its old position to
+         * the new position.
+         * <p>
+         * If this method returns true, ItemTouchHelper assumes {@code viewHolder} has been moved
+         * to the adapter position of {@code target} ViewHolder
+         * ({@link ViewHolder#getAdapterPosition()
+         * ViewHolder#getAdapterPosition()}).
+         * <p>
+         * If you don't support drag & drop, this method will never be called.
+         *
+         * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to.
+         * @param viewHolder   The ViewHolder which is being dragged by the user.
+         * @param target       The ViewHolder over which the currently active item is being
+         *                     dragged.
+         * @return True if the {@code viewHolder} has been moved to the adapter position of
+         * {@code target}.
+         * @see #onMoved(RecyclerView, ViewHolder, int, ViewHolder, int, int, int)
+         */
+        public abstract boolean onMove(RecyclerView recyclerView,
+                ViewHolder viewHolder, ViewHolder target);
+
+        /**
+         * Returns whether ItemTouchHelper should start a drag and drop operation if an item is
+         * long pressed.
+         * <p>
+         * Default value returns true but you may want to disable this if you want to start
+         * dragging on a custom view touch using {@link #startDrag(ViewHolder)}.
+         *
+         * @return True if ItemTouchHelper should start dragging an item when it is long pressed,
+         * false otherwise. Default value is <code>true</code>.
+         * @see #startDrag(ViewHolder)
+         */
+        public boolean isLongPressDragEnabled() {
+            return true;
+        }
+
+        /**
+         * Returns whether ItemTouchHelper should start a swipe operation if a pointer is swiped
+         * over the View.
+         * <p>
+         * Default value returns true but you may want to disable this if you want to start
+         * swiping on a custom view touch using {@link #startSwipe(ViewHolder)}.
+         *
+         * @return True if ItemTouchHelper should start swiping an item when user swipes a pointer
+         * over the View, false otherwise. Default value is <code>true</code>.
+         * @see #startSwipe(ViewHolder)
+         */
+        public boolean isItemViewSwipeEnabled() {
+            return true;
+        }
+
+        /**
+         * When finding views under a dragged view, by default, ItemTouchHelper searches for views
+         * that overlap with the dragged View. By overriding this method, you can extend or shrink
+         * the search box.
+         *
+         * @return The extra margin to be added to the hit box of the dragged View.
+         */
+        public int getBoundingBoxMargin() {
+            return 0;
+        }
+
+        /**
+         * Returns the fraction that the user should move the View to be considered as swiped.
+         * The fraction is calculated with respect to RecyclerView's bounds.
+         * <p>
+         * Default value is .5f, which means, to swipe a View, user must move the View at least
+         * half of RecyclerView's width or height, depending on the swipe direction.
+         *
+         * @param viewHolder The ViewHolder that is being dragged.
+         * @return A float value that denotes the fraction of the View size. Default value
+         * is .5f .
+         */
+        public float getSwipeThreshold(ViewHolder viewHolder) {
+            return .5f;
+        }
+
+        /**
+         * Returns the fraction that the user should move the View to be considered as it is
+         * dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views
+         * below it for a possible drop.
+         *
+         * @param viewHolder The ViewHolder that is being dragged.
+         * @return A float value that denotes the fraction of the View size. Default value is
+         * .5f .
+         */
+        public float getMoveThreshold(ViewHolder viewHolder) {
+            return .5f;
+        }
+
+        /**
+         * Defines the minimum velocity which will be considered as a swipe action by the user.
+         * <p>
+         * You can increase this value to make it harder to swipe or decrease it to make it easier.
+         * Keep in mind that ItemTouchHelper also checks the perpendicular velocity and makes sure
+         * current direction velocity is larger then the perpendicular one. Otherwise, user's
+         * movement is ambiguous. You can change the threshold by overriding
+         * {@link #getSwipeVelocityThreshold(float)}.
+         * <p>
+         * The velocity is calculated in pixels per second.
+         * <p>
+         * The default framework value is passed as a parameter so that you can modify it with a
+         * multiplier.
+         *
+         * @param defaultValue The default value (in pixels per second) used by the
+         *                     ItemTouchHelper.
+         * @return The minimum swipe velocity. The default implementation returns the
+         * <code>defaultValue</code> parameter.
+         * @see #getSwipeVelocityThreshold(float)
+         * @see #getSwipeThreshold(ViewHolder)
+         */
+        public float getSwipeEscapeVelocity(float defaultValue) {
+            return defaultValue;
+        }
+
+        /**
+         * Defines the maximum velocity ItemTouchHelper will ever calculate for pointer movements.
+         * <p>
+         * To consider a movement as swipe, ItemTouchHelper requires it to be larger than the
+         * perpendicular movement. If both directions reach to the max threshold, none of them will
+         * be considered as a swipe because it is usually an indication that user rather tried to
+         * scroll then swipe.
+         * <p>
+         * The velocity is calculated in pixels per second.
+         * <p>
+         * You can customize this behavior by changing this method. If you increase the value, it
+         * will be easier for the user to swipe diagonally and if you decrease the value, user will
+         * need to make a rather straight finger movement to trigger a swipe.
+         *
+         * @param defaultValue The default value(in pixels per second) used by the ItemTouchHelper.
+         * @return The velocity cap for pointer movements. The default implementation returns the
+         * <code>defaultValue</code> parameter.
+         * @see #getSwipeEscapeVelocity(float)
+         */
+        public float getSwipeVelocityThreshold(float defaultValue) {
+            return defaultValue;
+        }
+
+        /**
+         * Called by ItemTouchHelper to select a drop target from the list of ViewHolders that
+         * are under the dragged View.
+         * <p>
+         * Default implementation filters the View with which dragged item have changed position
+         * in the drag direction. For instance, if the view is dragged UP, it compares the
+         * <code>view.getTop()</code> of the two views before and after drag started. If that value
+         * is different, the target view passes the filter.
+         * <p>
+         * Among these Views which pass the test, the one closest to the dragged view is chosen.
+         * <p>
+         * This method is called on the main thread every time user moves the View. If you want to
+         * override it, make sure it does not do any expensive operations.
+         *
+         * @param selected    The ViewHolder being dragged by the user.
+         * @param dropTargets The list of ViewHolder that are under the dragged View and
+         *                    candidate as a drop.
+         * @param curX        The updated left value of the dragged View after drag translations
+         *                    are applied. This value does not include margins added by
+         *                    {@link RecyclerView.ItemDecoration}s.
+         * @param curY        The updated top value of the dragged View after drag translations
+         *                    are applied. This value does not include margins added by
+         *                    {@link RecyclerView.ItemDecoration}s.
+         * @return A ViewHolder to whose position the dragged ViewHolder should be
+         * moved to.
+         */
+        public ViewHolder chooseDropTarget(ViewHolder selected,
+                List<ViewHolder> dropTargets, int curX, int curY) {
+            int right = curX + selected.itemView.getWidth();
+            int bottom = curY + selected.itemView.getHeight();
+            ViewHolder winner = null;
+            int winnerScore = -1;
+            final int dx = curX - selected.itemView.getLeft();
+            final int dy = curY - selected.itemView.getTop();
+            final int targetsSize = dropTargets.size();
+            for (int i = 0; i < targetsSize; i++) {
+                final ViewHolder target = dropTargets.get(i);
+                if (dx > 0) {
+                    int diff = target.itemView.getRight() - right;
+                    if (diff < 0 && target.itemView.getRight() > selected.itemView.getRight()) {
+                        final int score = Math.abs(diff);
+                        if (score > winnerScore) {
+                            winnerScore = score;
+                            winner = target;
+                        }
+                    }
+                }
+                if (dx < 0) {
+                    int diff = target.itemView.getLeft() - curX;
+                    if (diff > 0 && target.itemView.getLeft() < selected.itemView.getLeft()) {
+                        final int score = Math.abs(diff);
+                        if (score > winnerScore) {
+                            winnerScore = score;
+                            winner = target;
+                        }
+                    }
+                }
+                if (dy < 0) {
+                    int diff = target.itemView.getTop() - curY;
+                    if (diff > 0 && target.itemView.getTop() < selected.itemView.getTop()) {
+                        final int score = Math.abs(diff);
+                        if (score > winnerScore) {
+                            winnerScore = score;
+                            winner = target;
+                        }
+                    }
+                }
+
+                if (dy > 0) {
+                    int diff = target.itemView.getBottom() - bottom;
+                    if (diff < 0 && target.itemView.getBottom() > selected.itemView.getBottom()) {
+                        final int score = Math.abs(diff);
+                        if (score > winnerScore) {
+                            winnerScore = score;
+                            winner = target;
+                        }
+                    }
+                }
+            }
+            return winner;
+        }
+
+        /**
+         * Called when a ViewHolder is swiped by the user.
+         * <p>
+         * If you are returning relative directions ({@link #START} , {@link #END}) from the
+         * {@link #getMovementFlags(RecyclerView, ViewHolder)} method, this method
+         * will also use relative directions. Otherwise, it will use absolute directions.
+         * <p>
+         * If you don't support swiping, this method will never be called.
+         * <p>
+         * ItemTouchHelper will keep a reference to the View until it is detached from
+         * RecyclerView.
+         * As soon as it is detached, ItemTouchHelper will call
+         * {@link #clearView(RecyclerView, ViewHolder)}.
+         *
+         * @param viewHolder The ViewHolder which has been swiped by the user.
+         * @param direction  The direction to which the ViewHolder is swiped. It is one of
+         *                   {@link #UP}, {@link #DOWN},
+         *                   {@link #LEFT} or {@link #RIGHT}. If your
+         *                   {@link #getMovementFlags(RecyclerView, ViewHolder)}
+         *                   method
+         *                   returned relative flags instead of {@link #LEFT} / {@link #RIGHT};
+         *                   `direction` will be relative as well. ({@link #START} or {@link
+         *                   #END}).
+         */
+        public abstract void onSwiped(ViewHolder viewHolder, int direction);
+
+        /**
+         * Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed.
+         * <p/>
+         * If you override this method, you should call super.
+         *
+         * @param viewHolder  The new ViewHolder that is being swiped or dragged. Might be null if
+         *                    it is cleared.
+         * @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE},
+         *                    {@link ItemTouchHelper#ACTION_STATE_SWIPE} or
+         *                    {@link ItemTouchHelper#ACTION_STATE_DRAG}.
+         * @see #clearView(RecyclerView, RecyclerView.ViewHolder)
+         */
+        public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
+            if (viewHolder != null) {
+                sUICallback.onSelected(viewHolder.itemView);
+            }
+        }
+
+        private int getMaxDragScroll(RecyclerView recyclerView) {
+            if (mCachedMaxScrollSpeed == -1) {
+                mCachedMaxScrollSpeed = recyclerView.getResources().getDimensionPixelSize(
+                        R.dimen.item_touch_helper_max_drag_scroll_per_frame);
+            }
+            return mCachedMaxScrollSpeed;
+        }
+
+        /**
+         * Called when {@link #onMove(RecyclerView, ViewHolder, ViewHolder)} returns true.
+         * <p>
+         * ItemTouchHelper does not create an extra Bitmap or View while dragging, instead, it
+         * modifies the existing View. Because of this reason, it is important that the View is
+         * still part of the layout after it is moved. This may not work as intended when swapped
+         * Views are close to RecyclerView bounds or there are gaps between them (e.g. other Views
+         * which were not eligible for dropping over).
+         * <p>
+         * This method is responsible to give necessary hint to the LayoutManager so that it will
+         * keep the View in visible area. For example, for LinearLayoutManager, this is as simple
+         * as calling {@link LinearLayoutManager#scrollToPositionWithOffset(int, int)}.
+         *
+         * Default implementation calls {@link RecyclerView#scrollToPosition(int)} if the View's
+         * new position is likely to be out of bounds.
+         * <p>
+         * It is important to ensure the ViewHolder will stay visible as otherwise, it might be
+         * removed by the LayoutManager if the move causes the View to go out of bounds. In that
+         * case, drag will end prematurely.
+         *
+         * @param recyclerView The RecyclerView controlled by the ItemTouchHelper.
+         * @param viewHolder   The ViewHolder under user's control.
+         * @param fromPos      The previous adapter position of the dragged item (before it was
+         *                     moved).
+         * @param target       The ViewHolder on which the currently active item has been dropped.
+         * @param toPos        The new adapter position of the dragged item.
+         * @param x            The updated left value of the dragged View after drag translations
+         *                     are applied. This value does not include margins added by
+         *                     {@link RecyclerView.ItemDecoration}s.
+         * @param y            The updated top value of the dragged View after drag translations
+         *                     are applied. This value does not include margins added by
+         *                     {@link RecyclerView.ItemDecoration}s.
+         */
+        public void onMoved(final RecyclerView recyclerView,
+                final ViewHolder viewHolder, int fromPos, final ViewHolder target, int toPos, int x,
+                int y) {
+            final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+            if (layoutManager instanceof ViewDropHandler) {
+                ((ViewDropHandler) layoutManager).prepareForDrop(viewHolder.itemView,
+                        target.itemView, x, y);
+                return;
+            }
+
+            // if layout manager cannot handle it, do some guesswork
+            if (layoutManager.canScrollHorizontally()) {
+                final int minLeft = layoutManager.getDecoratedLeft(target.itemView);
+                if (minLeft <= recyclerView.getPaddingLeft()) {
+                    recyclerView.scrollToPosition(toPos);
+                }
+                final int maxRight = layoutManager.getDecoratedRight(target.itemView);
+                if (maxRight >= recyclerView.getWidth() - recyclerView.getPaddingRight()) {
+                    recyclerView.scrollToPosition(toPos);
+                }
+            }
+
+            if (layoutManager.canScrollVertically()) {
+                final int minTop = layoutManager.getDecoratedTop(target.itemView);
+                if (minTop <= recyclerView.getPaddingTop()) {
+                    recyclerView.scrollToPosition(toPos);
+                }
+                final int maxBottom = layoutManager.getDecoratedBottom(target.itemView);
+                if (maxBottom >= recyclerView.getHeight() - recyclerView.getPaddingBottom()) {
+                    recyclerView.scrollToPosition(toPos);
+                }
+            }
+        }
+
+        void onDraw(Canvas c, RecyclerView parent, ViewHolder selected,
+                List<ItemTouchHelper.RecoverAnimation> recoverAnimationList,
+                int actionState, float dX, float dY) {
+            final int recoverAnimSize = recoverAnimationList.size();
+            for (int i = 0; i < recoverAnimSize; i++) {
+                final ItemTouchHelper.RecoverAnimation anim = recoverAnimationList.get(i);
+                anim.update();
+                final int count = c.save();
+                onChildDraw(c, parent, anim.mViewHolder, anim.mX, anim.mY, anim.mActionState,
+                        false);
+                c.restoreToCount(count);
+            }
+            if (selected != null) {
+                final int count = c.save();
+                onChildDraw(c, parent, selected, dX, dY, actionState, true);
+                c.restoreToCount(count);
+            }
+        }
+
+        void onDrawOver(Canvas c, RecyclerView parent, ViewHolder selected,
+                List<ItemTouchHelper.RecoverAnimation> recoverAnimationList,
+                int actionState, float dX, float dY) {
+            final int recoverAnimSize = recoverAnimationList.size();
+            for (int i = 0; i < recoverAnimSize; i++) {
+                final ItemTouchHelper.RecoverAnimation anim = recoverAnimationList.get(i);
+                final int count = c.save();
+                onChildDrawOver(c, parent, anim.mViewHolder, anim.mX, anim.mY, anim.mActionState,
+                        false);
+                c.restoreToCount(count);
+            }
+            if (selected != null) {
+                final int count = c.save();
+                onChildDrawOver(c, parent, selected, dX, dY, actionState, true);
+                c.restoreToCount(count);
+            }
+            boolean hasRunningAnimation = false;
+            for (int i = recoverAnimSize - 1; i >= 0; i--) {
+                final RecoverAnimation anim = recoverAnimationList.get(i);
+                if (anim.mEnded && !anim.mIsPendingCleanup) {
+                    recoverAnimationList.remove(i);
+                } else if (!anim.mEnded) {
+                    hasRunningAnimation = true;
+                }
+            }
+            if (hasRunningAnimation) {
+                parent.invalidate();
+            }
+        }
+
+        /**
+         * Called by the ItemTouchHelper when the user interaction with an element is over and it
+         * also completed its animation.
+         * <p>
+         * This is a good place to clear all changes on the View that was done in
+         * {@link #onSelectedChanged(RecyclerView.ViewHolder, int)},
+         * {@link #onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int,
+         * boolean)} or
+         * {@link #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean)}.
+         *
+         * @param recyclerView The RecyclerView which is controlled by the ItemTouchHelper.
+         * @param viewHolder   The View that was interacted by the user.
+         */
+        public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
+            sUICallback.clearView(viewHolder.itemView);
+        }
+
+        /**
+         * Called by ItemTouchHelper on RecyclerView's onDraw callback.
+         * <p>
+         * If you would like to customize how your View's respond to user interactions, this is
+         * a good place to override.
+         * <p>
+         * Default implementation translates the child by the given <code>dX</code>,
+         * <code>dY</code>.
+         * ItemTouchHelper also takes care of drawing the child after other children if it is being
+         * dragged. This is done using child re-ordering mechanism. On platforms prior to L, this
+         * is
+         * achieved via {@link android.view.ViewGroup#getChildDrawingOrder(int, int)} and on L
+         * and after, it changes View's elevation value to be greater than all other children.)
+         *
+         * @param c                 The canvas which RecyclerView is drawing its children
+         * @param recyclerView      The RecyclerView to which ItemTouchHelper is attached to
+         * @param viewHolder        The ViewHolder which is being interacted by the User or it was
+         *                          interacted and simply animating to its original position
+         * @param dX                The amount of horizontal displacement caused by user's action
+         * @param dY                The amount of vertical displacement caused by user's action
+         * @param actionState       The type of interaction on the View. Is either {@link
+         *                          #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}.
+         * @param isCurrentlyActive True if this view is currently being controlled by the user or
+         *                          false it is simply animating back to its original state.
+         * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
+         * boolean)
+         */
+        public void onChildDraw(Canvas c, RecyclerView recyclerView,
+                ViewHolder viewHolder,
+                float dX, float dY, int actionState, boolean isCurrentlyActive) {
+            sUICallback.onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
+                    isCurrentlyActive);
+        }
+
+        /**
+         * Called by ItemTouchHelper on RecyclerView's onDraw callback.
+         * <p>
+         * If you would like to customize how your View's respond to user interactions, this is
+         * a good place to override.
+         * <p>
+         * Default implementation translates the child by the given <code>dX</code>,
+         * <code>dY</code>.
+         * ItemTouchHelper also takes care of drawing the child after other children if it is being
+         * dragged. This is done using child re-ordering mechanism. On platforms prior to L, this
+         * is
+         * achieved via {@link android.view.ViewGroup#getChildDrawingOrder(int, int)} and on L
+         * and after, it changes View's elevation value to be greater than all other children.)
+         *
+         * @param c                 The canvas which RecyclerView is drawing its children
+         * @param recyclerView      The RecyclerView to which ItemTouchHelper is attached to
+         * @param viewHolder        The ViewHolder which is being interacted by the User or it was
+         *                          interacted and simply animating to its original position
+         * @param dX                The amount of horizontal displacement caused by user's action
+         * @param dY                The amount of vertical displacement caused by user's action
+         * @param actionState       The type of interaction on the View. Is either {@link
+         *                          #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}.
+         * @param isCurrentlyActive True if this view is currently being controlled by the user or
+         *                          false it is simply animating back to its original state.
+         * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
+         * boolean)
+         */
+        public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
+                ViewHolder viewHolder,
+                float dX, float dY, int actionState, boolean isCurrentlyActive) {
+            sUICallback.onDrawOver(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
+                    isCurrentlyActive);
+        }
+
+        /**
+         * Called by the ItemTouchHelper when user action finished on a ViewHolder and now the View
+         * will be animated to its final position.
+         * <p>
+         * Default implementation uses ItemAnimator's duration values. If
+         * <code>animationType</code> is {@link #ANIMATION_TYPE_DRAG}, it returns
+         * {@link RecyclerView.ItemAnimator#getMoveDuration()}, otherwise, it returns
+         * {@link RecyclerView.ItemAnimator#getRemoveDuration()}. If RecyclerView does not have
+         * any {@link RecyclerView.ItemAnimator} attached, this method returns
+         * {@code DEFAULT_DRAG_ANIMATION_DURATION} or {@code DEFAULT_SWIPE_ANIMATION_DURATION}
+         * depending on the animation type.
+         *
+         * @param recyclerView  The RecyclerView to which the ItemTouchHelper is attached to.
+         * @param animationType The type of animation. Is one of {@link #ANIMATION_TYPE_DRAG},
+         *                      {@link #ANIMATION_TYPE_SWIPE_CANCEL} or
+         *                      {@link #ANIMATION_TYPE_SWIPE_SUCCESS}.
+         * @param animateDx     The horizontal distance that the animation will offset
+         * @param animateDy     The vertical distance that the animation will offset
+         * @return The duration for the animation
+         */
+        public long getAnimationDuration(RecyclerView recyclerView, int animationType,
+                float animateDx, float animateDy) {
+            final RecyclerView.ItemAnimator itemAnimator = recyclerView.getItemAnimator();
+            if (itemAnimator == null) {
+                return animationType == ANIMATION_TYPE_DRAG ? DEFAULT_DRAG_ANIMATION_DURATION
+                        : DEFAULT_SWIPE_ANIMATION_DURATION;
+            } else {
+                return animationType == ANIMATION_TYPE_DRAG ? itemAnimator.getMoveDuration()
+                        : itemAnimator.getRemoveDuration();
+            }
+        }
+
+        /**
+         * Called by the ItemTouchHelper when user is dragging a view out of bounds.
+         * <p>
+         * You can override this method to decide how much RecyclerView should scroll in response
+         * to this action. Default implementation calculates a value based on the amount of View
+         * out of bounds and the time it spent there. The longer user keeps the View out of bounds,
+         * the faster the list will scroll. Similarly, the larger portion of the View is out of
+         * bounds, the faster the RecyclerView will scroll.
+         *
+         * @param recyclerView        The RecyclerView instance to which ItemTouchHelper is
+         *                            attached to.
+         * @param viewSize            The total size of the View in scroll direction, excluding
+         *                            item decorations.
+         * @param viewSizeOutOfBounds The total size of the View that is out of bounds. This value
+         *                            is negative if the View is dragged towards left or top edge.
+         * @param totalSize           The total size of RecyclerView in the scroll direction.
+         * @param msSinceStartScroll  The time passed since View is kept out of bounds.
+         * @return The amount that RecyclerView should scroll. Keep in mind that this value will
+         * be passed to {@link RecyclerView#scrollBy(int, int)} method.
+         */
+        public int interpolateOutOfBoundsScroll(RecyclerView recyclerView,
+                int viewSize, int viewSizeOutOfBounds,
+                int totalSize, long msSinceStartScroll) {
+            final int maxScroll = getMaxDragScroll(recyclerView);
+            final int absOutOfBounds = Math.abs(viewSizeOutOfBounds);
+            final int direction = (int) Math.signum(viewSizeOutOfBounds);
+            // might be negative if other direction
+            float outOfBoundsRatio = Math.min(1f, 1f * absOutOfBounds / viewSize);
+            final int cappedScroll = (int) (direction * maxScroll
+                    * sDragViewScrollCapInterpolator.getInterpolation(outOfBoundsRatio));
+            final float timeRatio;
+            if (msSinceStartScroll > DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS) {
+                timeRatio = 1f;
+            } else {
+                timeRatio = (float) msSinceStartScroll / DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS;
+            }
+            final int value = (int) (cappedScroll * sDragScrollInterpolator
+                    .getInterpolation(timeRatio));
+            if (value == 0) {
+                return viewSizeOutOfBounds > 0 ? 1 : -1;
+            }
+            return value;
+        }
+    }
+
+    /**
+     * A simple wrapper to the default Callback which you can construct with drag and swipe
+     * directions and this class will handle the flag callbacks. You should still override onMove
+     * or
+     * onSwiped depending on your use case.
+     *
+     * <pre>
+     * ItemTouchHelper mIth = new ItemTouchHelper(
+     *     new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
+     *         ItemTouchHelper.LEFT) {
+     *         public abstract boolean onMove(RecyclerView recyclerView,
+     *             ViewHolder viewHolder, ViewHolder target) {
+     *             final int fromPos = viewHolder.getAdapterPosition();
+     *             final int toPos = target.getAdapterPosition();
+     *             // move item in `fromPos` to `toPos` in adapter.
+     *             return true;// true if moved, false otherwise
+     *         }
+     *         public void onSwiped(ViewHolder viewHolder, int direction) {
+     *             // remove from adapter
+     *         }
+     * });
+     * </pre>
+     */
+    public abstract static class SimpleCallback extends Callback {
+
+        private int mDefaultSwipeDirs;
+
+        private int mDefaultDragDirs;
+
+        /**
+         * Creates a Callback for the given drag and swipe allowance. These values serve as
+         * defaults
+         * and if you want to customize behavior per ViewHolder, you can override
+         * {@link #getSwipeDirs(RecyclerView, ViewHolder)}
+         * and / or {@link #getDragDirs(RecyclerView, ViewHolder)}.
+         *
+         * @param dragDirs  Binary OR of direction flags in which the Views can be dragged. Must be
+         *                  composed of {@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link
+         *                  #END},
+         *                  {@link #UP} and {@link #DOWN}.
+         * @param swipeDirs Binary OR of direction flags in which the Views can be swiped. Must be
+         *                  composed of {@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link
+         *                  #END},
+         *                  {@link #UP} and {@link #DOWN}.
+         */
+        public SimpleCallback(int dragDirs, int swipeDirs) {
+            mDefaultSwipeDirs = swipeDirs;
+            mDefaultDragDirs = dragDirs;
+        }
+
+        /**
+         * Updates the default swipe directions. For example, you can use this method to toggle
+         * certain directions depending on your use case.
+         *
+         * @param defaultSwipeDirs Binary OR of directions in which the ViewHolders can be swiped.
+         */
+        public void setDefaultSwipeDirs(int defaultSwipeDirs) {
+            mDefaultSwipeDirs = defaultSwipeDirs;
+        }
+
+        /**
+         * Updates the default drag directions. For example, you can use this method to toggle
+         * certain directions depending on your use case.
+         *
+         * @param defaultDragDirs Binary OR of directions in which the ViewHolders can be dragged.
+         */
+        public void setDefaultDragDirs(int defaultDragDirs) {
+            mDefaultDragDirs = defaultDragDirs;
+        }
+
+        /**
+         * Returns the swipe directions for the provided ViewHolder.
+         * Default implementation returns the swipe directions that was set via constructor or
+         * {@link #setDefaultSwipeDirs(int)}.
+         *
+         * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to.
+         * @param viewHolder   The RecyclerView for which the swipe direction is queried.
+         * @return A binary OR of direction flags.
+         */
+        public int getSwipeDirs(RecyclerView recyclerView, ViewHolder viewHolder) {
+            return mDefaultSwipeDirs;
+        }
+
+        /**
+         * Returns the drag directions for the provided ViewHolder.
+         * Default implementation returns the drag directions that was set via constructor or
+         * {@link #setDefaultDragDirs(int)}.
+         *
+         * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to.
+         * @param viewHolder   The RecyclerView for which the swipe direction is queried.
+         * @return A binary OR of direction flags.
+         */
+        public int getDragDirs(RecyclerView recyclerView, ViewHolder viewHolder) {
+            return mDefaultDragDirs;
+        }
+
+        @Override
+        public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
+            return makeMovementFlags(getDragDirs(recyclerView, viewHolder),
+                    getSwipeDirs(recyclerView, viewHolder));
+        }
+    }
+
+    private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
+
+        ItemTouchHelperGestureListener() {
+        }
+
+        @Override
+        public boolean onDown(MotionEvent e) {
+            return true;
+        }
+
+        @Override
+        public void onLongPress(MotionEvent e) {
+            View child = findChildView(e);
+            if (child != null) {
+                ViewHolder vh = mRecyclerView.getChildViewHolder(child);
+                if (vh != null) {
+                    if (!mCallback.hasDragFlag(mRecyclerView, vh)) {
+                        return;
+                    }
+                    int pointerId = e.getPointerId(0);
+                    // Long press is deferred.
+                    // Check w/ active pointer id to avoid selecting after motion
+                    // event is canceled.
+                    if (pointerId == mActivePointerId) {
+                        final int index = e.findPointerIndex(mActivePointerId);
+                        final float x = e.getX(index);
+                        final float y = e.getY(index);
+                        mInitialTouchX = x;
+                        mInitialTouchY = y;
+                        mDx = mDy = 0f;
+                        if (DEBUG) {
+                            Log.d(TAG,
+                                    "onlong press: x:" + mInitialTouchX + ",y:" + mInitialTouchY);
+                        }
+                        if (mCallback.isLongPressDragEnabled()) {
+                            select(vh, ACTION_STATE_DRAG);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private class RecoverAnimation implements Animator.AnimatorListener {
+
+        final float mStartDx;
+
+        final float mStartDy;
+
+        final float mTargetX;
+
+        final float mTargetY;
+
+        final ViewHolder mViewHolder;
+
+        final int mActionState;
+
+        private final ValueAnimator mValueAnimator;
+
+        final int mAnimationType;
+
+        public boolean mIsPendingCleanup;
+
+        float mX;
+
+        float mY;
+
+        // if user starts touching a recovering view, we put it into interaction mode again,
+        // instantly.
+        boolean mOverridden = false;
+
+        boolean mEnded = false;
+
+        private float mFraction;
+
+        RecoverAnimation(ViewHolder viewHolder, int animationType,
+                int actionState, float startDx, float startDy, float targetX, float targetY) {
+            mActionState = actionState;
+            mAnimationType = animationType;
+            mViewHolder = viewHolder;
+            mStartDx = startDx;
+            mStartDy = startDy;
+            mTargetX = targetX;
+            mTargetY = targetY;
+            mValueAnimator = ValueAnimator.ofFloat(0f, 1f);
+            mValueAnimator.addUpdateListener(
+                    new ValueAnimator.AnimatorUpdateListener() {
+                        @Override
+                        public void onAnimationUpdate(ValueAnimator animation) {
+                            setFraction(animation.getAnimatedFraction());
+                        }
+                    });
+            mValueAnimator.setTarget(viewHolder.itemView);
+            mValueAnimator.addListener(this);
+            setFraction(0f);
+        }
+
+        public void setDuration(long duration) {
+            mValueAnimator.setDuration(duration);
+        }
+
+        public void start() {
+            mViewHolder.setIsRecyclable(false);
+            mValueAnimator.start();
+        }
+
+        public void cancel() {
+            mValueAnimator.cancel();
+        }
+
+        public void setFraction(float fraction) {
+            mFraction = fraction;
+        }
+
+        /**
+         * We run updates on onDraw method but use the fraction from animator callback.
+         * This way, we can sync translate x/y values w/ the animators to avoid one-off frames.
+         */
+        public void update() {
+            if (mStartDx == mTargetX) {
+                mX = mViewHolder.itemView.getTranslationX();
+            } else {
+                mX = mStartDx + mFraction * (mTargetX - mStartDx);
+            }
+            if (mStartDy == mTargetY) {
+                mY = mViewHolder.itemView.getTranslationY();
+            } else {
+                mY = mStartDy + mFraction * (mTargetY - mStartDy);
+            }
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!mEnded) {
+                mViewHolder.setIsRecyclable(true);
+            }
+            mEnded = true;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            setFraction(1f); //make sure we recover the view's state.
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/helper/ItemTouchUIUtil.java b/core/java/com/android/internal/widget/helper/ItemTouchUIUtil.java
new file mode 100644
index 0000000..e368a6d
--- /dev/null
+++ b/core/java/com/android/internal/widget/helper/ItemTouchUIUtil.java
@@ -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.
+ */
+
+package com.android.internal.widget.helper;
+
+import android.graphics.Canvas;
+import android.view.View;
+
+import com.android.internal.widget.RecyclerView;
+
+/**
+ * Utility class for {@link ItemTouchHelper} which handles item transformations for different
+ * API versions.
+ * <p/>
+ * This class has methods that map to {@link ItemTouchHelper.Callback}'s drawing methods. Default
+ * implementations in {@link ItemTouchHelper.Callback} call these methods with
+ * {@link RecyclerView.ViewHolder#itemView} and {@link ItemTouchUIUtil} makes necessary changes
+ * on the View depending on the API level. You can access the instance of {@link ItemTouchUIUtil}
+ * via {@link ItemTouchHelper.Callback#getDefaultUIUtil()} and call its methods with the children
+ * of ViewHolder that you want to apply default effects.
+ *
+ * @see ItemTouchHelper.Callback#getDefaultUIUtil()
+ */
+public interface ItemTouchUIUtil {
+
+    /**
+     * The default implementation for {@link ItemTouchHelper.Callback#onChildDraw(Canvas,
+     * RecyclerView, RecyclerView.ViewHolder, float, float, int, boolean)}
+     */
+    void onDraw(Canvas c, RecyclerView recyclerView, View view,
+            float dX, float dY, int actionState, boolean isCurrentlyActive);
+
+    /**
+     * The default implementation for {@link ItemTouchHelper.Callback#onChildDrawOver(Canvas,
+     * RecyclerView, RecyclerView.ViewHolder, float, float, int, boolean)}
+     */
+    void onDrawOver(Canvas c, RecyclerView recyclerView, View view,
+            float dX, float dY, int actionState, boolean isCurrentlyActive);
+
+    /**
+     * The default implementation for {@link ItemTouchHelper.Callback#clearView(RecyclerView,
+     * RecyclerView.ViewHolder)}
+     */
+    void clearView(View view);
+
+    /**
+     * The default implementation for {@link ItemTouchHelper.Callback#onSelectedChanged(
+     * RecyclerView.ViewHolder, int)}
+     */
+    void onSelected(View view);
+}
+
diff --git a/core/java/com/android/internal/widget/helper/ItemTouchUIUtilImpl.java b/core/java/com/android/internal/widget/helper/ItemTouchUIUtilImpl.java
new file mode 100644
index 0000000..0de240b
--- /dev/null
+++ b/core/java/com/android/internal/widget/helper/ItemTouchUIUtilImpl.java
@@ -0,0 +1,84 @@
+/*
+ * 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.widget.helper;
+
+import android.graphics.Canvas;
+import android.view.View;
+
+import com.android.internal.R;
+import com.android.internal.widget.RecyclerView;
+
+/**
+ * Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them
+ * public API, which is not desired in this case.
+ */
+class ItemTouchUIUtilImpl implements ItemTouchUIUtil {
+    @Override
+    public void onDraw(Canvas c, RecyclerView recyclerView, View view,
+            float dX, float dY, int actionState, boolean isCurrentlyActive) {
+        if (isCurrentlyActive) {
+            Object originalElevation = view.getTag(
+                    R.id.item_touch_helper_previous_elevation);
+            if (originalElevation == null) {
+                originalElevation = view.getElevation();
+                float newElevation = 1f + findMaxElevation(recyclerView, view);
+                view.setElevation(newElevation);
+                view.setTag(R.id.item_touch_helper_previous_elevation,
+                        originalElevation);
+            }
+        }
+        view.setTranslationX(dX);
+        view.setTranslationY(dY);
+    }
+
+    private float findMaxElevation(RecyclerView recyclerView, View itemView) {
+        final int childCount = recyclerView.getChildCount();
+        float max = 0;
+        for (int i = 0; i < childCount; i++) {
+            final View child = recyclerView.getChildAt(i);
+            if (child == itemView) {
+                continue;
+            }
+            final float elevation = child.getElevation();
+            if (elevation > max) {
+                max = elevation;
+            }
+        }
+        return max;
+    }
+
+    @Override
+    public void clearView(View view) {
+        final Object tag = view.getTag(
+                R.id.item_touch_helper_previous_elevation);
+        if (tag != null && tag instanceof Float) {
+            view.setElevation((Float) tag);
+        }
+        view.setTag(R.id.item_touch_helper_previous_elevation, null);
+        view.setTranslationX(0f);
+        view.setTranslationY(0f);
+    }
+
+    @Override
+    public void onSelected(View view) {
+    }
+
+    @Override
+    public void onDrawOver(Canvas c, RecyclerView recyclerView,
+            View view, float dX, float dY, int actionState, boolean isCurrentlyActive) {
+    }
+}
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 06ef4c9..03f2bc1 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Slog;
@@ -50,16 +51,20 @@
         SocketTagger.set(new NetworkManagementSocketTagger());
     }
 
-    public static void setThreadSocketStatsTag(int tag) {
+    public static int setThreadSocketStatsTag(int tag) {
+        final int old = threadSocketTags.get().statsTag;
         threadSocketTags.get().statsTag = tag;
+        return old;
     }
 
     public static int getThreadSocketStatsTag() {
         return threadSocketTags.get().statsTag;
     }
 
-    public static void setThreadSocketStatsUid(int uid) {
+    public static int setThreadSocketStatsUid(int uid) {
+        final int old = threadSocketTags.get().statsUid;
         threadSocketTags.get().statsUid = uid;
+        return old;
     }
 
     @Override
@@ -69,6 +74,9 @@
             Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
                     + Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid);
         }
+        if (options.statsTag == -1 && StrictMode.vmUntaggedSocketEnabled()) {
+            StrictMode.onUntaggedSocket();
+        }
         // TODO: skip tagging when options would be no-op
         tagSocketFd(fd, options.statsTag, options.statsUid);
     }
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 168da5f..fcb4c7b 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -109,6 +109,10 @@
     // background while in data-usage save mode, as read from the configuration files.
     final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
 
+    // These are the action strings of broadcasts which are whitelisted to
+    // be delivered anonymously even to apps which target O+.
+    final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
+
     // These are the package names of apps which should be in the 'always'
     // URL-handling state upon factory reset.
     final ArraySet<String> mLinkedApps = new ArraySet<>();
@@ -162,6 +166,10 @@
         return mPermissions;
     }
 
+    public ArraySet<String> getAllowImplicitBroadcasts() {
+        return mAllowImplicitBroadcasts;
+    }
+
     public ArraySet<String> getAllowInPowerSaveExceptIdle() {
         return mAllowInPowerSaveExceptIdle;
     }
@@ -438,6 +446,17 @@
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
+                } else if ("allow-implicit-broadcast".equals(name) && allowAll) {
+                    String action = parser.getAttributeValue(null, "action");
+                    if (action == null) {
+                        Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mAllowImplicitBroadcasts.add(action);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
                 } else if ("app-link".equals(name) && allowAppConfigs) {
                     String pkgname = parser.getAttributeValue(null, "package");
                     if (pkgname == null) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 68034f6..327f142 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -118,7 +118,6 @@
     android/graphics/ColorFilter.cpp \
     android/graphics/DrawFilter.cpp \
     android/graphics/FontFamily.cpp \
-    android/graphics/FontUtils.cpp \
     android/graphics/CreateJavaOutputStreamAdaptor.cpp \
     android/graphics/GIFMovie.cpp \
     android/graphics/GraphicBuffer.cpp \
@@ -159,6 +158,7 @@
     android_hardware_camera2_legacy_LegacyCameraDevice.cpp \
     android_hardware_camera2_legacy_PerfMeasurement.cpp \
     android_hardware_camera2_DngCreator.cpp \
+    android_hardware_HardwareBuffer.cpp \
     android_hardware_Radio.cpp \
     android_hardware_SensorManager.cpp \
     android_hardware_SerialPort.cpp \
@@ -238,6 +238,7 @@
     libnativehelper \
     liblog \
     libcutils \
+    libdebuggerd_client \
     libutils \
     libbinder \
     libui \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index fb5d037..340f2ee 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -87,6 +87,7 @@
 extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env);
 extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env);
 extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
+extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
 extern int register_android_hardware_Radio(JNIEnv *env);
 extern int register_android_hardware_SensorManager(JNIEnv *env);
 extern int register_android_hardware_SerialPort(JNIEnv *env);
@@ -1373,6 +1374,7 @@
     REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice),
     REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement),
     REG_JNI(register_android_hardware_camera2_DngCreator),
+    REG_JNI(register_android_hardware_HardwareBuffer),
     REG_JNI(register_android_hardware_Radio),
     REG_JNI(register_android_hardware_SensorManager),
     REG_JNI(register_android_hardware_SerialPort),
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 685c93d..ac8f413 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -30,7 +30,6 @@
 #include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/AssetManager.h>
 #include "Utils.h"
-#include "FontUtils.h"
 
 #include <hwui/MinikinSkia.h>
 #include <hwui/Typeface.h>
@@ -40,54 +39,27 @@
 
 namespace android {
 
-struct NativeFamilyBuilder {
-    uint32_t langId;
-    int variant;
-    std::vector<minikin::Font> fonts;
-};
-
-static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
-    NativeFamilyBuilder* builder = new NativeFamilyBuilder();
-    if (lang != nullptr) {
-        ScopedUtfChars str(env, lang);
-        builder->langId = minikin::FontStyle::registerLanguageList(str.c_str());
-    } else {
-        builder->langId = minikin::FontStyle::registerLanguageList("");
+static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
+    if (lang == NULL) {
+        return (jlong)new minikin::FontFamily(variant);
     }
-    builder->variant = variant;
-    return reinterpret_cast<jlong>(builder);
+    ScopedUtfChars str(env, lang);
+    uint32_t langId = minikin::FontStyle::registerLanguageList(str.c_str());
+    return (jlong)new minikin::FontFamily(langId, variant);
 }
 
-static jlong FontFamily_create(jlong builderPtr) {
-    if (builderPtr == 0) {
-        return 0;
-    }
-    NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-    minikin::FontFamily* family = new minikin::FontFamily(
-            builder->langId, builder->variant, std::move(builder->fonts));
-    delete builder;
-    return reinterpret_cast<jlong>(family);
-}
-
-static void FontFamily_unref(jlong familyPtr) {
+static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
     minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
     fontFamily->Unref();
 }
 
-static void addSkTypeface(jlong builderPtr, sk_sp<SkTypeface> face, const void* fontData,
-        size_t fontSize, int ttcIndex) {
+static jboolean addSkTypeface(minikin::FontFamily* family, sk_sp<SkTypeface> face,
+        const void* fontData, size_t fontSize, int ttcIndex) {
     minikin::MinikinFont* minikinFont =
             new MinikinFontSkia(std::move(face), fontData, fontSize, ttcIndex);
-    NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-    int weight;
-    bool italic;
-    if (!minikin::FontFamily::analyzeStyle(minikinFont, &weight, &italic)) {
-        ALOGE("analyzeStyle failed. Using default style");
-        weight = 400;
-        italic = false;
-    }
-    builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight / 100, italic)));
+    bool result = family->addFont(minikinFont);
     minikinFont->Unref();
+    return result;
 }
 
 static void release_global_ref(const void* /*data*/, void* context) {
@@ -113,7 +85,7 @@
     }
 }
 
-static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong builderPtr, jobject bytebuf,
+static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jobject bytebuf,
         jint ttcIndex) {
     NPE_CHECK_RETURN_ZERO(env, bytebuf);
     const void* fontPtr = env->GetDirectBufferAddress(bytebuf);
@@ -140,11 +112,21 @@
         ALOGE("addFont failed to create font");
         return false;
     }
-    addSkTypeface(builderPtr, std::move(face), fontPtr, (size_t)fontSize, ttcIndex);
-    return true;
+    minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
+    return addSkTypeface(fontFamily, std::move(face), fontPtr, (size_t)fontSize, ttcIndex);
 }
 
-static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr,
+static struct {
+    jmethodID mGet;
+    jmethodID mSize;
+} gListClassInfo;
+
+static struct {
+    jfieldID mTag;
+    jfieldID mStyleValue;
+} gAxisClassInfo;
+
+static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
         jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
     NPE_CHECK_RETURN_ZERO(env, font);
 
@@ -152,22 +134,20 @@
     std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes;
     int skiaAxesLength = 0;
     if (listOfAxis) {
-        ListHelper list(env, listOfAxis);
-        jint listSize = list.size();
+        jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize);
 
         skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]);
         skiaAxesLength = listSize;
         for (jint i = 0; i < listSize; ++i) {
-            jobject axisObject = list.get(i);
+            jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i);
             if (!axisObject) {
                 skiaAxes[i].fTag = 0;
                 skiaAxes[i].fStyleValue = 0;
                 continue;
             }
-            AxisHelper axis(env, axisObject);
 
-            jint tag = axis.getTag();
-            jfloat stylevalue = axis.getStyleValue();
+            jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag);
+            jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue);
             skiaAxes[i].fTag = tag;
             skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue);
         }
@@ -198,11 +178,10 @@
         ALOGE("addFont failed to create font, invalid request");
         return false;
     }
+    minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
     minikin::MinikinFont* minikinFont =
-            new MinikinFontSkia(std::move(face), fontPtr, fontSize, ttcIndex);
-    NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-    builder->fonts.push_back(minikin::Font(minikinFont,
-            minikin::FontStyle(weight / 100, isItalic)));
+            new MinikinFontSkia(std::move(face), fontPtr, (size_t)fontSize, ttcIndex);
+    fontFamily->addFont(minikinFont, minikin::FontStyle(weight / 100, isItalic));
     minikinFont->Unref();
     return true;
 }
@@ -211,8 +190,8 @@
     delete static_cast<Asset*>(context);
 }
 
-static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong builderPtr,
-        jobject jassetMgr, jstring jpath) {
+static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong familyPtr,
+        jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset) {
     NPE_CHECK_RETURN_ZERO(env, jassetMgr);
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
@@ -222,7 +201,18 @@
     }
 
     ScopedUtfChars str(env, jpath);
-    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (str.c_str() == nullptr) {
+        return false;
+    }
+
+    Asset* asset;
+    if (isAsset) {
+        asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    } else {
+        asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
+                Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
+    }
+
     if (NULL == asset) {
         return false;
     }
@@ -243,22 +233,20 @@
         ALOGE("addFontFromAsset failed to create font %s", str.c_str());
         return false;
     }
-
-    addSkTypeface(builderPtr, std::move(face), buf, bufSize, 0 /* ttc index */);
-    return true;
+    minikin::FontFamily* fontFamily = reinterpret_cast<minikin::FontFamily*>(familyPtr);
+    return addSkTypeface(fontFamily, std::move(face), buf, bufSize, /* ttcIndex */ 0);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 static const JNINativeMethod gFontFamilyMethods[] = {
-    { "nInitBuilder",          "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder },
-    { "nCreateFamily",         "(J)J", (void*)FontFamily_create },
+    { "nCreateFamily",         "(Ljava/lang/String;I)J", (void*)FontFamily_create },
     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
     { "nAddFont",              "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont },
     { "nAddFontWeightStyle",   "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
             (void*)FontFamily_addFontWeightStyle },
-    { "nAddFontFromAsset",     "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
-            (void*)FontFamily_addFontFromAsset },
+    { "nAddFontFromAssetManager",     "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZ)Z",
+            (void*)FontFamily_addFontFromAssetManager },
 };
 
 int register_android_graphics_FontFamily(JNIEnv* env)
@@ -266,7 +254,14 @@
     int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
             NELEM(gFontFamilyMethods));
 
-    init_FontUtils(env);
+    jclass listClass = FindClassOrDie(env, "java/util/List");
+    gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
+    gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
+
+    jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis");
+    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I");
+    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F");
+
     return err;
 }
 
diff --git a/core/jni/android/graphics/FontUtils.cpp b/core/jni/android/graphics/FontUtils.cpp
index 11c2d29..91fec2a 100644
--- a/core/jni/android/graphics/FontUtils.cpp
+++ b/core/jni/android/graphics/FontUtils.cpp
@@ -55,9 +55,9 @@
     gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;");
     gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I");
 
-    jclass axisClass = FindClassOrDie(env, "android/graphics/FontListParser$Axis");
-    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I");
-    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F");
+    jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis");
+    gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I");
+    gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F");
 }
 
 }  // namespace android
diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h
deleted file mode 100644
index 6fbd5e3..0000000
--- a/core/jni/android/graphics/FontUtils.h
+++ /dev/null
@@ -1,54 +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.
- */
-
-#ifndef _ANDROID_GRAPHICS_FONT_UTILS_H_
-#define _ANDROID_GRAPHICS_FONT_UTILS_H_
-
-#include <jni.h>
-
-namespace android {
-
-// Utility wrapper for java.util.List
-class ListHelper {
-public:
-  ListHelper(JNIEnv* env, jobject list) : mEnv(env), mList(list) {}
-
-  jint size() const;
-  jobject get(jint index) const;
-
-private:
-  JNIEnv* mEnv;
-  jobject mList;
-};
-
-// Utility wrapper for android.graphics.FontListParser$Axis
-class AxisHelper {
-public:
-  AxisHelper(JNIEnv* env, jobject axis) : mEnv(env), mAxis(axis) {}
-
-  jint getTag() const;
-  jfloat getStyleValue() const;
-
-private:
-  JNIEnv* mEnv;
-  jobject mAxis;
-};
-
-void init_FontUtils(JNIEnv* env);
-
-}; // namespace android
-
-#endif  // _ANDROID_GRAPHICS_FONT_UTILS_H_
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 0a0fce3e..c920b8d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -17,14 +17,12 @@
 #include "jni.h"
 #include "core_jni_helpers.h"
 
-#include "FontUtils.h"
 #include "GraphicsJNI.h"
 #include "ScopedPrimitiveArray.h"
 #include "SkTypeface.h"
 #include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/AssetManager.h>
 #include <hwui/Typeface.h>
-#include <minikin/FontFamily.h>
 
 using namespace android;
 
@@ -42,23 +40,6 @@
     return reinterpret_cast<jlong>(face);
 }
 
-static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
-        jobject listOfAxis) {
-    std::vector<minikin::FontVariation> variations;
-    ListHelper list(env, listOfAxis);
-    for (jint i = 0; i < list.size(); i++) {
-        jobject axisObject = list.get(i);
-        if (axisObject == nullptr) {
-            continue;
-        }
-        AxisHelper axis(env, axisObject);
-        variations.push_back(minikin::FontVariation(axis.getTag(), axis.getStyleValue()));
-    }
-    Typeface* baseTypeface = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* result = Typeface::createFromTypefaceWithVariation(baseTypeface, variations);
-    return reinterpret_cast<jlong>(result);
-}
-
 static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
     Typeface* face = Typeface::createWeightAlias(family, weight);
@@ -96,8 +77,6 @@
 
 static const JNINativeMethod gTypefaceMethods[] = {
     { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
-    { "nativeCreateFromTypefaceWithVariation", "(JLjava/util/List;)J",
-            (void*)Typeface_createFromTypefaceWithVariation },
     { "nativeCreateWeightAlias",  "(JI)J", (void*)Typeface_createWeightAlias },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(J)I",  (void*)Typeface_getStyle },
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 9ce5670..c49287c 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -63,97 +63,87 @@
     get_canvas(canvasHandle)->setBitmap(bitmap);
 }
 
-static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
+static jboolean isOpaque(jlong canvasHandle) {
     return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
 }
 
-static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
+static jint getWidth(jlong canvasHandle) {
     return static_cast<jint>(get_canvas(canvasHandle)->width());
 }
 
-static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
+static jint getHeight(jlong canvasHandle) {
     return static_cast<jint>(get_canvas(canvasHandle)->height());
 }
 
-static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) {
+static void setHighContrastText(jlong canvasHandle, jboolean highContrastText) {
     Canvas* canvas = get_canvas(canvasHandle);
     canvas->setHighContrastText(highContrastText);
 }
 
-static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
-    return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
-}
-
-static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
+static jint save(jlong canvasHandle, jint flagsHandle) {
     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
 }
 
-static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
+static jint saveLayer(jlong canvasHandle, jfloat l, jfloat t,
                       jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
     Paint* paint  = reinterpret_cast<Paint*>(paintHandle);
     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
 }
 
-static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
+static jint saveLayerAlpha(jlong canvasHandle, jfloat l, jfloat t,
                            jfloat r, jfloat b, jint alpha, jint flagsHandle) {
     SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
 }
 
-static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
+static bool restore(jlong canvasHandle) {
     Canvas* canvas = get_canvas(canvasHandle);
-    if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
-        if (throwOnUnderflow) {
-            doThrowISE(env, "Underflow in restore - more restores than saves");
-        }
-        return; // compat behavior - return without throwing
+    if (canvas->getSaveCount() <= 1) {
+        return false; // cannot restore anymore
     }
     canvas->restore();
+    return true; // success
 }
 
-static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
-        jboolean throwOnUnderflow) {
+static void restoreToCount(jlong canvasHandle, jint saveCount) {
     Canvas* canvas = get_canvas(canvasHandle);
-    if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
-        if (throwOnUnderflow) {
-            doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
-            return;
-        }
-        restoreCount = 1; // compat behavior - restore as far as possible
-    }
-    canvas->restoreToCount(restoreCount);
+    canvas->restoreToCount(saveCount);
 }
 
-static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
+static jint getSaveCount(jlong canvasHandle) {
+    return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
+}
+
+static void getMatrix(jlong canvasHandle, jlong matrixHandle) {
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     get_canvas(canvasHandle)->getMatrix(matrix);
 }
 
-static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
+static void setMatrix(jlong canvasHandle, jlong matrixHandle) {
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
 }
 
-static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
+static void concat(jlong canvasHandle, jlong matrixHandle) {
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     get_canvas(canvasHandle)->concat(*matrix);
 }
 
-static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
+static void rotate(jlong canvasHandle, jfloat degrees) {
     get_canvas(canvasHandle)->rotate(degrees);
 }
 
-static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
+static void scale(jlong canvasHandle, jfloat sx, jfloat sy) {
     get_canvas(canvasHandle)->scale(sx, sy);
 }
 
-static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
+static void skew(jlong canvasHandle, jfloat sx, jfloat sy) {
     get_canvas(canvasHandle)->skew(sx, sy);
 }
 
-static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
+static void translate(jlong canvasHandle, jfloat dx, jfloat dy) {
     get_canvas(canvasHandle)->translate(dx, dy);
 }
 
@@ -171,13 +161,13 @@
     return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
+static jboolean quickRejectRect(jlong canvasHandle,
                                 jfloat left, jfloat top, jfloat right, jfloat bottom) {
     bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
     return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
+static jboolean quickRejectPath(jlong canvasHandle, jlong pathHandle) {
     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
     bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
     return result ? JNI_TRUE : JNI_FALSE;
@@ -205,14 +195,14 @@
     return static_cast<SkClipOp>(rgnOp);
 }
 
-static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
+static jboolean clipRect(jlong canvasHandle, jfloat l, jfloat t,
                          jfloat r, jfloat b, jint opHandle) {
     bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
             opHandleToClipOp(opHandle));
     return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
+static jboolean clipPath(jlong canvasHandle, jlong pathHandle,
                          jint opHandle) {
     SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
     bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
@@ -565,7 +555,7 @@
     env->ReleaseStringChars(text, jchars);
 }
 
-static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
+static void setDrawFilter(jlong canvasHandle, jlong filterHandle) {
     get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
 }
 
@@ -587,6 +577,9 @@
 
     // ------------ @FastNative ----------------
     {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
+    {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
+
+    // ------------ @CriticalNative ----------------
     {"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
     {"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
     {"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
@@ -595,16 +588,15 @@
     {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
     {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
-    {"nRestore","(JZ)V", (void*) CanvasJNI::restore},
-    {"nRestoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount},
-    {"nGetCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
+    {"nRestore","(J)Z", (void*) CanvasJNI::restore},
+    {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
+    {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
     {"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
     {"nConcat","(JJ)V", (void*) CanvasJNI::concat},
     {"nRotate","(JF)V", (void*) CanvasJNI::rotate},
     {"nScale","(JFF)V", (void*) CanvasJNI::scale},
     {"nSkew","(JFF)V", (void*) CanvasJNI::skew},
     {"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
-    {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
     {"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
     {"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
     {"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
new file mode 100644
index 0000000..74527d9
--- /dev/null
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "HardwareBuffer"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "android_os_Parcel.h"
+#include "android/graphics/GraphicsJNI.h"
+
+#include <android/hardware_buffer.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+
+#include <binder/Parcel.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+#include <ui/GraphicBuffer.h>
+
+#include <private/gui/ComposerService.h>
+
+#include "core_jni_helpers.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+// Defines
+// ----------------------------------------------------------------------------
+
+// Debug
+static const bool kDebugGraphicBuffer = false;
+
+// ----------------------------------------------------------------------------
+// Types
+// ----------------------------------------------------------------------------
+
+static struct {
+    jclass clazz;
+    jfieldID mNativeObject;
+    jmethodID ctor;
+} gHardwareBufferClassInfo;
+
+class GraphicBufferWrapper {
+public:
+    explicit GraphicBufferWrapper(const sp<GraphicBuffer>& buffer)
+            : buffer(buffer) {}
+
+    sp<GraphicBuffer> buffer;
+};
+
+
+// ----------------------------------------------------------------------------
+// Helper functions
+// ----------------------------------------------------------------------------
+
+static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
+    return (mask & bitsToCheck) == bitsToCheck;
+}
+
+// ----------------------------------------------------------------------------
+// HardwareBuffer lifecycle
+// ----------------------------------------------------------------------------
+
+static jlong android_hardware_HardwareBuffer_create(JNIEnv* env, jobject clazz,
+        jint width, jint height, jint format, jint layers, jlong usage) {
+
+    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+    sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
+    if (alloc == NULL) {
+        if (kDebugGraphicBuffer) {
+            ALOGW("createGraphicBufferAlloc() failed in HardwareBuffer.create()");
+        }
+        return NULL;
+    }
+
+    // TODO: update createGraphicBuffer to take two 64-bit values.
+    int pixelFormat = android_hardware_HardwareBuffer_convertToPixelFormat(format);
+    if (pixelFormat == 0) {
+        if (kDebugGraphicBuffer) {
+            ALOGW("createGraphicBufferAlloc() invalid pixel format in HardwareBuffer.create()");
+        }
+        return NULL;
+    }
+    uint32_t grallocUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(usage, 0);
+    status_t error;
+    sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, pixelFormat,
+            layers, grallocUsage, &error));
+    if (buffer == NULL) {
+        if (kDebugGraphicBuffer) {
+            ALOGW("createGraphicBuffer() failed in HardwareBuffer.create()");
+        }
+        return NULL;
+    }
+
+    GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
+    return reinterpret_cast<jlong>(wrapper);
+}
+
+static void destroyWrapper(GraphicBufferWrapper* wrapper) {
+    delete wrapper;
+}
+
+static jlong android_hardware_HardwareBuffer_getNativeFinalizer(JNIEnv* env,
+        jobject clazz) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyWrapper));
+}
+
+//----------------------------------------------------------------------------
+// Accessors
+// ----------------------------------------------------------------------------
+
+static inline GraphicBuffer* GraphicBufferWrapper_to_GraphicBuffer(
+        jlong nativeObject) {
+    return reinterpret_cast<GraphicBufferWrapper*>(nativeObject)->buffer.get();
+}
+
+static jint android_hardware_HardwareBuffer_getWidth(JNIEnv* env, jobject clazz,
+    jlong nativeObject) {
+    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+    return static_cast<jint>(buffer->getWidth());
+}
+
+static jint android_hardware_HardwareBuffer_getHeight(JNIEnv* env,
+    jobject clazz, jlong nativeObject) {
+    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+    return static_cast<jint>(buffer->getHeight());
+}
+
+static jint android_hardware_HardwareBuffer_getFormat(JNIEnv* env,
+    jobject clazz, jlong nativeObject) {
+    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+    return static_cast<jint>(android_hardware_HardwareBuffer_convertFromPixelFormat(
+            buffer->getPixelFormat()));
+}
+
+static jint android_hardware_HardwareBuffer_getLayers(JNIEnv* env,
+    jobject clazz, jlong nativeObject) {
+    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+    return static_cast<jint>(buffer->getLayerCount());
+}
+
+static jlong android_hardware_HardwareBuffer_getUsage(JNIEnv* env,
+    jobject clazz, jlong nativeObject) {
+    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+    return android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+            buffer->getUsage());
+}
+
+// ----------------------------------------------------------------------------
+// Serialization
+// ----------------------------------------------------------------------------
+
+static void android_hardware_HardwareBuffer_write(JNIEnv* env, jobject clazz,
+        jlong nativeObject, jobject dest) {
+    GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(nativeObject);
+    Parcel* parcel = parcelForJavaObject(env, dest);
+    if (parcel) {
+        parcel->write(*buffer);
+    }
+}
+
+static jlong android_hardware_HardwareBuffer_read(JNIEnv* env, jobject clazz,
+        jobject in) {
+    Parcel* parcel = parcelForJavaObject(env, in);
+    if (parcel) {
+        sp<GraphicBuffer> buffer = new GraphicBuffer();
+        parcel->read(*buffer);
+        return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
+    }
+
+    return NULL;
+}
+
+// ----------------------------------------------------------------------------
+// Public functions
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+AHardwareBuffer* android_hardware_HardwareBuffer_getNativeHardwareBuffer(
+        JNIEnv* env, jobject hardwareBufferObj) {
+    if (env->IsInstanceOf(hardwareBufferObj, gHardwareBufferClassInfo.clazz)) {
+        GraphicBuffer* buffer = GraphicBufferWrapper_to_GraphicBuffer(
+                env->GetLongField(hardwareBufferObj, gHardwareBufferClassInfo.mNativeObject));
+        return reinterpret_cast<AHardwareBuffer*>(buffer);
+    } else {
+        return nullptr;
+    }
+}
+
+jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+        JNIEnv* env, AHardwareBuffer* hardwareBuffer) {
+    GraphicBuffer* buffer = reinterpret_cast<GraphicBuffer*>(hardwareBuffer);
+    GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
+    jobject hardwareBufferObj = env->NewObject(gHardwareBufferClassInfo.clazz,
+            gHardwareBufferClassInfo.ctor, reinterpret_cast<jlong>(wrapper));
+    if (hardwareBufferObj == NULL) {
+        delete wrapper;
+        if (env->ExceptionCheck()) {
+            ALOGE("Could not create instance of HardwareBuffer from AHardwareBuffer.");
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+        return nullptr;
+    }
+    return hardwareBufferObj;
+}
+
+uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(uint32_t format) {
+    switch (format) {
+        case PIXEL_FORMAT_RGBA_8888:
+            return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+        case PIXEL_FORMAT_RGBX_8888:
+            return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
+        case PIXEL_FORMAT_RGB_565:
+            return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+        case PIXEL_FORMAT_RGB_888:
+            return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+        case PIXEL_FORMAT_RGBA_FP16:
+            return AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT;
+        default:
+            ALOGE("Unknown pixel format %u", format);
+            return 0;
+    }
+}
+
+uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(uint32_t format) {
+    switch (format) {
+        case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+            return PIXEL_FORMAT_RGBA_8888;
+        case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+            return PIXEL_FORMAT_RGBX_8888;
+        case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+            return PIXEL_FORMAT_RGB_565;
+        case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+            return PIXEL_FORMAT_RGB_888;
+        case AHARDWAREBUFFER_FORMAT_R16G16B16A16_SFLOAT:
+            return PIXEL_FORMAT_RGBA_FP16;
+        default:
+            ALOGE("Unknown AHardwareBuffer format %u", format);
+            return 0;
+    }
+}
+
+uint32_t android_hardware_HardwareBuffer_convertToGrallocUsageBits(uint64_t usage0,
+        uint64_t usage1) {
+    uint32_t bits = 0;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ))
+        bits |= GRALLOC_USAGE_SW_READ_RARELY;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN))
+        bits |= GRALLOC_USAGE_SW_READ_OFTEN;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE))
+        bits |= GRALLOC_USAGE_SW_WRITE_RARELY;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN))
+        bits |= GRALLOC_USAGE_SW_WRITE_OFTEN;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE))
+        bits |= GRALLOC_USAGE_HW_TEXTURE;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT))
+        bits |= GRALLOC_USAGE_HW_RENDER;
+    // 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_VIDEO_ENCODE))
+        bits |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
+    if (containsBits(usage0, AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT))
+        bits |= GRALLOC_USAGE_PROTECTED;
+
+    (void)usage1;
+
+    return bits;
+}
+
+uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(uint64_t usage0) {
+    uint64_t bits = 0;
+    if (containsBits(usage0, GRALLOC_USAGE_SW_READ_RARELY))
+        bits |= AHARDWAREBUFFER_USAGE0_CPU_READ;
+    if (containsBits(usage0, GRALLOC_USAGE_SW_READ_OFTEN))
+        bits |= AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
+    if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_RARELY))
+        bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE;
+    if (containsBits(usage0, GRALLOC_USAGE_SW_WRITE_OFTEN))
+        bits |= AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN;
+    if (containsBits(usage0, GRALLOC_USAGE_HW_TEXTURE))
+        bits |= AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE;
+    if (containsBits(usage0, GRALLOC_USAGE_HW_RENDER))
+        bits |= AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT;
+    if (containsBits(usage0, GRALLOC_USAGE_HW_VIDEO_ENCODER))
+        bits |= AHARDWAREBUFFER_USAGE0_VIDEO_ENCODE;
+    if (containsBits(usage0, GRALLOC_USAGE_PROTECTED))
+        bits |= AHARDWAREBUFFER_USAGE0_PROTECTED_CONTENT;
+
+    return bits;
+}
+
+}  // namespace android
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/hardware/HardwareBuffer";
+
+static const JNINativeMethod gMethods[] = {
+    { "nCreateHardwareBuffer",  "(IIIIJ)J", (void*) android_hardware_HardwareBuffer_create },
+    { "nGetNativeFinalizer", "()J",          (void*) android_hardware_HardwareBuffer_getNativeFinalizer },
+    { "nWriteHardwareBufferToParcel",  "(JLandroid/os/Parcel;)V",
+            (void*) android_hardware_HardwareBuffer_write },
+    { "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J",
+            (void*) android_hardware_HardwareBuffer_read },
+
+    // --------------- @FastNative ----------------------
+    { "nGetWidth", "(J)I",                   (void*) android_hardware_HardwareBuffer_getWidth },
+    { "nGetHeight", "(J)I",                  (void*) android_hardware_HardwareBuffer_getHeight },
+    { "nGetFormat", "(J)I",                  (void*) android_hardware_HardwareBuffer_getFormat },
+    { "nGetLayers", "(J)I",                  (void*) android_hardware_HardwareBuffer_getLayers },
+    { "nGetUsage", "(J)J",                  (void*) android_hardware_HardwareBuffer_getUsage },
+};
+
+int register_android_hardware_HardwareBuffer(JNIEnv* env) {
+    int err = RegisterMethodsOrDie(env, kClassPathName, gMethods,
+            NELEM(gMethods));
+
+    jclass clazz = FindClassOrDie(env, "android/hardware/HardwareBuffer");
+    gHardwareBufferClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
+    gHardwareBufferClassInfo.mNativeObject = GetFieldIDOrDie(env,
+            gHardwareBufferClassInfo.clazz, "mNativeObject", "J");
+    gHardwareBufferClassInfo.ctor = GetMethodIDOrDie(env,
+            gHardwareBufferClassInfo.clazz, "<init>", "(J)V");
+
+    return err;
+}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 14d7e81..be3a87b 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,7 +33,7 @@
 #include <string>
 
 #include <android-base/stringprintf.h>
-#include <cutils/debugger.h>
+#include <debuggerd/client.h>
 #include <log/log.h>
 #include <utils/misc.h>
 #include <utils/String8.h>
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 0b4fbcc..8a7600b 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -144,26 +144,22 @@
     return ctx.write();
 }
 
-/*
- * In class android.util.EventLog:
- *  static native void readEvents(int[] tags, Collection<Event> output)
- *
- *  Reads events from the event log
- */
-static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED,
-                                             jintArray tags,
-                                             jobject out) {
-
-    if (tags == NULL || out == NULL) {
-        jniThrowNullPointerException(env, NULL);
+static void readEvents(JNIEnv* env, int loggerMode, jintArray tags, jlong startTime, jobject out) {
+    struct logger_list *logger_list;
+    if (startTime) {
+        logger_list = android_logger_list_alloc_time(loggerMode,
+                log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0);
+    } else {
+        logger_list = android_logger_list_alloc(loggerMode, 0, 0);
+    }
+    if (!logger_list) {
+        jniThrowIOException(env, errno);
         return;
     }
 
-    struct logger_list *logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0);
-
-    if (!logger_list) {
+    if (!android_logger_open(logger_list, LOG_ID_EVENTS)) {
         jniThrowIOException(env, errno);
+        android_logger_list_free(logger_list);
         return;
     }
 
@@ -228,6 +224,41 @@
 }
 
 /*
+ * In class android.util.EventLog:
+ *  static native void readEvents(int[] tags, Collection<Event> output)
+ *
+ *  Reads events from the event log
+ */
+static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz UNUSED,
+                                             jintArray tags,
+                                             jobject out) {
+
+    if (tags == NULL || out == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+
+    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tags, 0, out);
+ }
+/*
+ * In class android.util.EventLog:
+ *  static native void readEventsOnWrapping(int[] tags, long timestamp, Collection<Event> output)
+ *
+ *  Reads events from the event log, blocking until events after timestamp are to be overwritten.
+ */
+static void android_util_EventLog_readEventsOnWrapping(JNIEnv* env, jobject clazz UNUSED,
+                                             jintArray tags,
+                                             jlong timestamp,
+                                             jobject out) {
+    if (tags == NULL || out == NULL) {
+        jniThrowNullPointerException(env, NULL);
+        return;
+    }
+    readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_WRAP,
+            tags, timestamp, out);
+}
+
+/*
  * JNI registration.
  */
 static const JNINativeMethod gRegisterMethods[] = {
@@ -247,6 +278,10 @@
       "([ILjava/util/Collection;)V",
       (void*) android_util_EventLog_readEvents
     },
+    { "readEventsOnWrapping",
+      "([IJLjava/util/Collection;)V",
+      (void*) android_util_EventLog_readEventsOnWrapping
+    },
 };
 
 static struct { const char *name; jclass *clazz; } gClasses[] = {
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 6b634df..4150636 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -78,6 +78,9 @@
 
 status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
         PointerIcon* outPointerIcon) {
+    if (!pointerIconObj) {
+        return BAD_VALUE;
+    }
     outPointerIcon->style = env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType);
     outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
     outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index d75d5c1..3eccc42 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -88,6 +88,7 @@
         return;
     }
 
+    node->setStagingDisplayList(nullptr, nullptr);
     // Update the valid field, since native has already removed
     // the staging DisplayList
     env->SetBooleanField(jnode, gRenderNode_validFieldID, false);
diff --git a/core/jni/com_android_internal_os_FuseAppLoop.cpp b/core/jni/com_android_internal_os_FuseAppLoop.cpp
index 92a6934..dd003eb 100644
--- a/core/jni/com_android_internal_os_FuseAppLoop.cpp
+++ b/core/jni/com_android_internal_os_FuseAppLoop.cpp
@@ -51,7 +51,6 @@
     JNIEnv* const mEnv;
     jobject const mSelf;
     ScopedLocalRef<jbyteArray> mJniBuffer;
-    bool mActive;
 
     template <typename T>
     T checkException(T result) const {
@@ -67,8 +66,7 @@
     Callback(JNIEnv* env, jobject self) :
         mEnv(env),
         mSelf(self),
-        mJniBuffer(env, nullptr),
-        mActive(true) {}
+        mJniBuffer(env, nullptr) {}
 
     bool Init() {
         mJniBuffer.reset(mEnv->NewByteArray(kBufferSize));
@@ -76,7 +74,7 @@
     }
 
     bool IsActive() override {
-        return mActive;
+        return true;
     }
 
     int64_t OnGetSize(uint64_t inode) override {
@@ -92,10 +90,7 @@
     }
 
     int32_t OnRelease(uint64_t inode) override {
-        if (checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode)) == -1) {
-            mActive = false;
-        }
-        return fuse::kFuseSuccess;
+        return checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode));
     }
 
     int32_t OnRead(uint64_t inode, uint64_t offset, uint32_t size, void* buffer) override {
diff --git a/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
new file mode 100644
index 0000000..60e065c
--- /dev/null
+++ b/core/jni/include/android_runtime/android_hardware_HardwareBuffer.h
@@ -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.
+ */
+
+#ifndef _ANDROID_HARDWARE_HARDWAREBUFFER_H
+#define _ANDROID_HARDWARE_HARDWAREBUFFER_H
+
+#include <android/hardware_buffer.h>
+
+#include "jni.h"
+
+namespace android {
+
+/* Gets the underlying AHardwareBuffer for a HardwareBuffer. */
+extern AHardwareBuffer* android_hardware_HardwareBuffer_getNativeHardwareBuffer(
+        JNIEnv* env, jobject hardwareBufferObj);
+
+/* Returns a HardwareBuffer wrapper for the underlying AHardwareBuffer. */
+extern jobject android_hardware_HardwareBuffer_createFromAHardwareBuffer(
+        JNIEnv* env, AHardwareBuffer* hardwareBuffer);
+
+/* Convert from HAL_PIXEL_FORMAT values to AHARDWAREBUFFER_FORMAT values. */
+extern uint32_t android_hardware_HardwareBuffer_convertFromPixelFormat(
+      uint32_t format);
+
+/* Convert from AHARDWAREBUFFER_FORMAT values to HAL_PIXEL_FORMAT values. */
+extern uint32_t android_hardware_HardwareBuffer_convertToPixelFormat(
+      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);
+
+/* Convert from gralloc usage flags to to AHARDWAREBUFFER_USAGE0* flags. */
+extern uint64_t android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+      uint64_t usage0);
+
+} // namespace android
+
+#endif // _ANDROID_HARDWARE_HARDWAREBUFFER_H
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ec2f32b..ac9ebe0 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -21,6 +21,8 @@
 
 import "frameworks/base/libs/incident/proto/android/privacy.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/providers/settings.proto";
 
 package android.os;
 
@@ -49,4 +51,6 @@
 
     // System Services
     android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000;
+    android.service.NetworkStatsServiceDumpProto netstats = 3001;
+    android.providers.settings.SettingsServiceDumpProto settings = 3002;
 }
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
new file mode 100644
index 0000000..7674d7a
--- /dev/null
+++ b/core/proto/android/providers/settings.proto
@@ -0,0 +1,605 @@
+/*
+ * 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.providers.settings;
+
+option java_multiple_files = true;
+option java_outer_classname = "SettingsServiceProto";
+
+message SettingsServiceDumpProto {
+    // Per user settings
+    repeated UserSettingsProto user_settings = 1;
+
+    // Global settings
+    GlobalSettingsProto global_settings = 2;
+}
+
+message UserSettingsProto {
+    // Should be 0, 10, 11, 12, etc. where 0 is the owner.
+    int32 user_id = 1;
+
+    // The secure settings for this user
+    SecureSettingsProto secure_settings = 2;
+
+    // The system settings for this user
+    SystemSettingsProto system_settings = 3;
+}
+
+message GlobalSettingsProto {
+    // Historical operations
+    repeated SettingsOperationProto historical_op = 1;
+
+    SettingProto add_users_when_locked = 2;
+    SettingProto enable_accessibility_global_gesture_enabled = 3;
+    SettingProto airplane_mode_on = 4;
+    SettingProto theater_mode_on = 5;
+    SettingProto radio_bluetooth = 6;
+    SettingProto radio_wifi = 7;
+    SettingProto radio_wimax = 8;
+    SettingProto radio_cell = 9;
+    SettingProto radio_nfc = 10;
+    SettingProto airplane_mode_radios = 11;
+    SettingProto airplane_mode_toggleable_radios = 12;
+    SettingProto bluetooth_disabled_profiles = 13;
+    SettingProto bluetooth_interoperability_list = 14;
+    SettingProto wifi_sleep_policy = 15;
+    SettingProto auto_time = 16;
+    SettingProto auto_time_zone = 17;
+    SettingProto car_dock_sound = 18;
+    SettingProto car_undock_sound = 19;
+    SettingProto desk_dock_sound = 20;
+    SettingProto desk_undock_sound = 21;
+    SettingProto dock_sounds_enabled = 22;
+    SettingProto dock_sounds_enabled_when_accessibility = 23;
+    SettingProto lock_sound = 24;
+    SettingProto unlock_sound = 25;
+    SettingProto trusted_sound = 26;
+    SettingProto low_battery_sound = 27;
+    SettingProto power_sounds_enabled = 28;
+    SettingProto wireless_charging_started_sound = 29;
+    SettingProto charging_sounds_enabled = 30;
+    SettingProto stay_on_while_plugged_in = 31;
+    SettingProto bugreport_in_power_menu = 32;
+    SettingProto adb_enabled = 33;
+    SettingProto debug_view_attributes = 34;
+    SettingProto assisted_gps_enabled = 35;
+    SettingProto bluetooth_on = 36;
+    SettingProto cdma_cell_broadcast_sms = 37;
+    SettingProto cdma_roaming_mode = 38;
+    SettingProto cdma_subscription_mode = 39;
+    SettingProto data_activity_timeout_mobile = 40;
+    SettingProto data_activity_timeout_wifi = 41;
+    SettingProto data_roaming = 42;
+    SettingProto mdc_initial_max_retry = 43;
+    SettingProto force_allow_on_external = 44;
+    SettingProto development_force_resizable_activities = 45;
+    SettingProto development_enable_freeform_windows_support = 46;
+    SettingProto development_settings_enabled = 47;
+    SettingProto device_provisioned = 48;
+    SettingProto device_provisioning_mobile_data_enabled = 49;
+    SettingProto display_size_forced = 50;
+    SettingProto display_scaling_force = 51;
+    SettingProto download_max_bytes_over_mobile = 52;
+    SettingProto download_recommended_max_bytes_over_mobile = 53;
+    SettingProto hdmi_control_enabled = 54;
+    SettingProto hdmi_system_audio_enabled = 55;
+    SettingProto hdmi_control_auto_wakeup_enabled = 56;
+    SettingProto hdmi_control_auto_device_off_enabled = 57;
+    SettingProto mhl_input_switching_enabled = 58;
+    SettingProto mhl_power_charge_enabled = 59;
+    SettingProto mobile_data = 60;
+    SettingProto mobile_data_always_on = 61;
+    SettingProto connectivity_metrics_buffer_size = 62;
+    SettingProto netstats_enabled = 63;
+    SettingProto netstats_poll_interval = 64;
+    SettingProto netstats_time_cache_max_age = 65;
+    SettingProto netstats_global_alert_bytes = 66;
+    SettingProto netstats_sample_enabled = 67;
+    SettingProto netstats_dev_bucket_duration = 68;
+    SettingProto netstats_dev_persist_bytes = 69;
+    SettingProto netstats_dev_rotate_age = 70;
+    SettingProto netstats_dev_delete_age = 71;
+    SettingProto netstats_uid_bucket_duration = 72;
+    SettingProto netstats_uid_persist_bytes = 73;
+    SettingProto netstats_uid_rotate_age = 74;
+    SettingProto netstats_uid_delete_age = 75;
+    SettingProto netstats_uid_tag_bucket_duration = 76;
+    SettingProto netstats_uid_tag_persist_bytes = 77;
+    SettingProto netstats_uid_tag_rotate_age = 78;
+    SettingProto netstats_uid_tag_delete_age = 79;
+    SettingProto network_preference = 80;
+    SettingProto network_scorer_app = 81;
+    SettingProto nitz_update_diff = 82;
+    SettingProto nitz_update_spacing = 83;
+    SettingProto ntp_server = 84;
+    SettingProto ntp_timeout = 85;
+    SettingProto storage_benchmark_interval = 86;
+    SettingProto dns_resolver_sample_validity_seconds = 87;
+    SettingProto dns_resolver_success_threshold_percent = 88;
+    SettingProto dns_resolver_min_samples = 89;
+    SettingProto dns_resolver_max_samples = 90;
+    SettingProto ota_disable_automatic_update = 91;
+    SettingProto package_verifier_enable = 92;
+    SettingProto package_verifier_timeout = 93;
+    SettingProto package_verifier_default_response = 94;
+    SettingProto package_verifier_setting_visible = 95;
+    SettingProto package_verifier_include_adb = 96;
+    SettingProto fstrim_mandatory_interval = 97;
+    SettingProto pdp_watchdog_poll_interval_ms = 98;
+    SettingProto pdp_watchdog_long_poll_interval_ms = 99;
+    SettingProto pdp_watchdog_error_poll_interval_ms = 100;
+    SettingProto pdp_watchdog_trigger_packet_count = 101;
+    SettingProto pdp_watchdog_error_poll_count = 102;
+    SettingProto pdp_watchdog_max_pdp_reset_fail_count = 103;
+    SettingProto sampling_profiler_ms = 104;
+    SettingProto setup_prepaid_data_service_url = 105;
+    SettingProto setup_prepaid_detection_target_url = 106;
+    SettingProto setup_prepaid_detection_redir_host = 107;
+    SettingProto sms_outgoing_check_interval_ms = 108;
+    SettingProto sms_outgoing_check_max_count = 109;
+    SettingProto sms_short_code_confirmation = 110;
+    SettingProto sms_short_code_rule = 111;
+    SettingProto tcp_default_init_rwnd = 112;
+    SettingProto tether_supported = 113;
+    SettingProto tether_dun_required = 114;
+    SettingProto tether_dun_apn = 115;
+    SettingProto carrier_app_whitelist = 116;
+    SettingProto usb_mass_storage_enabled = 117;
+    SettingProto use_google_mail = 118;
+    SettingProto webview_data_reduction_proxy_key = 119;
+    SettingProto webview_fallback_logic_enabled = 120;
+    SettingProto webview_provider = 121;
+    SettingProto webview_multiprocess = 122;
+    SettingProto network_switch_notification_daily_limit = 123;
+    SettingProto network_switch_notification_rate_limit_millis = 124;
+    SettingProto network_avoid_bad_wifi = 125;
+    SettingProto wifi_display_on = 126;
+    SettingProto wifi_display_certification_on = 127;
+    SettingProto wifi_display_wps_config = 128;
+    SettingProto wifi_networks_available_notification_on = 129;
+    SettingProto wimax_networks_available_notification_on = 130;
+    SettingProto wifi_networks_available_repeat_delay = 131;
+    SettingProto wifi_country_code = 132;
+    SettingProto wifi_framework_scan_interval_ms = 133;
+    SettingProto wifi_idle_ms = 134;
+    SettingProto wifi_num_open_networks_kept = 135;
+    SettingProto wifi_on = 136;
+    SettingProto wifi_scan_always_available = 137;
+    SettingProto wifi_wakeup_enabled = 138;
+    SettingProto network_recommendations_enabled = 139;
+    SettingProto ble_scan_always_available = 140;
+    SettingProto wifi_saved_state = 141;
+    SettingProto wifi_supplicant_scan_interval_ms = 142;
+    SettingProto wifi_enhanced_auto_join = 143;
+    SettingProto wifi_network_show_rssi = 144;
+    SettingProto wifi_scan_interval_when_p2p_connected_ms = 145;
+    SettingProto wifi_watchdog_on = 146;
+    SettingProto wifi_watchdog_poor_network_test_enabled = 147;
+    SettingProto wifi_suspend_optimizations_enabled = 148;
+    SettingProto wifi_verbose_logging_enabled = 149;
+    SettingProto wifi_max_dhcp_retry_count = 150;
+    SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 151;
+    SettingProto wifi_device_owner_configs_lockdown = 152;
+    SettingProto wifi_frequency_band = 153;
+    SettingProto wifi_p2p_device_name = 154;
+    SettingProto wifi_reenable_delay_ms = 155;
+    SettingProto wifi_ephemeral_out_of_range_timeout_ms = 156;
+    SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 157;
+    SettingProto data_stall_alarm_aggressive_delay_in_ms = 158;
+    SettingProto provisioning_apn_alarm_delay_in_ms = 159;
+    SettingProto gprs_register_check_period_ms = 160;
+    SettingProto wtf_is_fatal = 161;
+    SettingProto mode_ringer = 162;
+    SettingProto overlay_display_devices = 163;
+    SettingProto battery_discharge_duration_threshold = 164;
+    SettingProto battery_discharge_threshold = 165;
+    SettingProto send_action_app_error = 166;
+    SettingProto dropbox_age_seconds = 167;
+    SettingProto dropbox_max_files = 168;
+    SettingProto dropbox_quota_kb = 169;
+    SettingProto dropbox_quota_percent = 170;
+    SettingProto dropbox_reserve_percent = 171;
+    SettingProto dropbox_tag_prefix = 172;
+    SettingProto error_logcat_prefix = 173;
+    SettingProto sys_free_storage_log_interval = 174;
+    SettingProto disk_free_change_reporting_threshold = 175;
+    SettingProto sys_storage_threshold_percentage = 176;
+    SettingProto sys_storage_threshold_max_bytes = 177;
+    SettingProto sys_storage_full_threshold_bytes = 178;
+    SettingProto sync_max_retry_delay_in_seconds = 179;
+    SettingProto connectivity_change_delay = 180;
+    SettingProto connectivity_sampling_interval_in_seconds = 181;
+    SettingProto pac_change_delay = 182;
+    SettingProto captive_portal_mode = 183;
+    SettingProto captive_portal_server = 184;
+    SettingProto captive_portal_https_url = 185;
+    SettingProto captive_portal_http_url = 186;
+    SettingProto captive_portal_fallback_url = 187;
+    SettingProto captive_portal_use_https = 188;
+    SettingProto captive_portal_user_agent = 189;
+    SettingProto nsd_on = 190;
+    SettingProto set_install_location = 191;
+    SettingProto default_install_location = 192;
+    SettingProto inet_condition_debounce_up_delay = 193;
+    SettingProto inet_condition_debounce_down_delay = 194;
+    SettingProto read_external_storage_enforced_default = 195;
+    SettingProto http_proxy = 196;
+    SettingProto global_http_proxy_host = 197;
+    SettingProto global_http_proxy_port = 198;
+    SettingProto global_http_proxy_exclusion_list = 199;
+    SettingProto global_http_proxy_pac = 200;
+    SettingProto set_global_http_proxy = 201;
+    SettingProto default_dns_server = 202;
+    SettingProto bluetooth_headset_priority_prefix = 203;
+    SettingProto bluetooth_a2dp_sink_priority_prefix = 204;
+    SettingProto bluetooth_a2dp_src_priority_prefix = 205;
+    SettingProto bluetooth_input_device_priority_prefix = 206;
+    SettingProto bluetooth_map_priority_prefix = 207;
+    SettingProto bluetooth_map_client_priority_prefix = 208;
+    SettingProto bluetooth_pbap_client_priority_prefix = 209;
+    SettingProto bluetooth_sap_priority_prefix = 210;
+    SettingProto bluetooth_pan_priority_prefix = 211;
+    SettingProto device_idle_constants = 212;
+    SettingProto device_idle_constants_watch = 213;
+    SettingProto app_idle_constants = 214;
+    SettingProto alarm_manager_constants = 215;
+    SettingProto job_scheduler_constants = 216;
+    SettingProto shortcut_manager_constants = 217;
+    SettingProto window_animation_scale = 218;
+    SettingProto transition_animation_scale = 219;
+    SettingProto animator_duration_scale = 220;
+    SettingProto fancy_ime_animations = 221;
+    SettingProto compatibility_mode = 222;
+    SettingProto emergency_tone = 223;
+    SettingProto call_auto_retry = 224;
+    SettingProto emergency_affordance_needed = 225;
+    SettingProto preferred_network_mode = 226;
+    SettingProto debug_app = 227;
+    SettingProto wait_for_debugger = 228;
+    SettingProto low_power_mode = 229;
+    SettingProto low_power_mode_trigger_level = 230;
+    SettingProto always_finish_activities = 231;
+    SettingProto dock_audio_media_enabled = 232;
+    SettingProto encoded_surround_output = 233;
+    SettingProto audio_safe_volume_state = 234;
+    SettingProto tzinfo_update_content_url = 235;
+    SettingProto tzinfo_update_metadata_url = 236;
+    SettingProto selinux_update_content_url = 237;
+    SettingProto selinux_update_metadata_url = 238;
+    SettingProto sms_short_codes_update_content_url = 239;
+    SettingProto sms_short_codes_update_metadata_url = 240;
+    SettingProto apn_db_update_content_url = 241;
+    SettingProto apn_db_update_metadata_url = 242;
+    SettingProto cert_pin_update_content_url = 243;
+    SettingProto cert_pin_update_metadata_url = 244;
+    SettingProto intent_firewall_update_content_url = 245;
+    SettingProto intent_firewall_update_metadata_url = 246;
+    SettingProto selinux_status = 247;
+    SettingProto development_force_rtl = 248;
+    SettingProto low_battery_sound_timeout = 249;
+    SettingProto wifi_bounce_delay_override_ms = 250;
+    SettingProto policy_control = 251;
+    SettingProto zen_mode = 252;
+    SettingProto zen_mode_ringer_level = 253;
+    SettingProto zen_mode_config_etag = 254;
+    SettingProto heads_up_notifications_enabled = 255;
+    SettingProto device_name = 256;
+    SettingProto network_scoring_provisioned = 257;
+    SettingProto require_password_to_decrypt = 258;
+    SettingProto enhanced_4g_mode_enabled = 259;
+    SettingProto vt_ims_enabled = 260;
+    SettingProto wfc_ims_enabled = 261;
+    SettingProto wfc_ims_mode = 262;
+    SettingProto wfc_ims_roaming_mode = 263;
+    SettingProto wfc_ims_roaming_enabled = 264;
+    SettingProto lte_service_forced = 265;
+    SettingProto ephemeral_cookie_max_size_bytes = 266;
+    SettingProto enable_ephemeral_feature = 267;
+    SettingProto uninstalled_ephemeral_app_cache_duration_millis = 268;
+    SettingProto allow_user_switching_when_system_user_locked = 269;
+    SettingProto boot_count = 270;
+    SettingProto safe_boot_disallowed = 271;
+    SettingProto device_demo_mode = 272;
+    SettingProto retail_demo_mode_constants = 273;
+    SettingProto database_downgrade_reason = 274;
+    SettingProto contacts_database_wal_enabled = 275;
+    SettingProto multi_sim_voice_call_subscription = 276;
+    SettingProto multi_sim_voice_prompt = 277;
+    SettingProto multi_sim_data_call_subscription = 278;
+    SettingProto multi_sim_sms_subscription = 279;
+    SettingProto multi_sim_sms_prompt = 280;
+    SettingProto new_contact_aggregator = 281;
+    SettingProto contact_metadata_sync_enabled = 282;
+    SettingProto enable_cellular_on_boot = 283;
+    SettingProto max_notification_enqueue_rate = 284;
+    SettingProto cell_on = 285;
+}
+
+message SecureSettingsProto {
+    // Historical operations
+    repeated SettingsOperationProto historical_op = 1;
+
+    SettingProto android_id = 2;
+    SettingProto default_input_method = 3;
+    SettingProto selected_input_method_subtype = 4;
+    SettingProto input_methods_subtype_history = 5;
+    SettingProto input_method_selector_visibility = 6;
+    SettingProto voice_interaction_service = 7;
+    SettingProto auto_fill_service = 8;
+    SettingProto bluetooth_hci_log = 9;
+    SettingProto user_setup_complete = 10;
+    SettingProto completed_category_prefix = 11;
+    SettingProto enabled_input_methods = 12;
+    SettingProto disabled_system_input_methods = 13;
+    SettingProto show_ime_with_hard_keyboard = 14;
+    SettingProto always_on_vpn_app = 15;
+    SettingProto always_on_vpn_lockdown = 16;
+    SettingProto install_non_market_apps = 17;
+    SettingProto location_mode = 18;
+    SettingProto location_previous_mode = 19;
+    SettingProto lock_to_app_exit_locked = 20;
+    SettingProto lock_screen_lock_after_timeout = 21;
+    SettingProto lock_screen_allow_remote_input = 22;
+    SettingProto show_note_about_notification_hiding = 23;
+    SettingProto trust_agents_initialized = 24;
+    SettingProto parental_control_enabled = 25;
+    SettingProto parental_control_last_update = 26;
+    SettingProto parental_control_redirect_url = 27;
+    SettingProto settings_classname = 28;
+    SettingProto accessibility_enabled = 29;
+    SettingProto touch_exploration_enabled = 30;
+    SettingProto enabled_accessibility_services = 31;
+    SettingProto touch_exploration_granted_accessibility_services = 32;
+    SettingProto accessibility_speak_password = 33;
+    SettingProto accessibility_high_text_contrast_enabled = 34;
+    SettingProto accessibility_script_injection = 35;
+    SettingProto accessibility_screen_reader_url = 36;
+    SettingProto accessibility_web_content_key_bindings = 37;
+    SettingProto accessibility_display_magnification_enabled = 38;
+    SettingProto accessibility_display_magnification_scale = 39;
+    SettingProto accessibility_soft_keyboard_mode = 40;
+    SettingProto accessibility_captioning_enabled = 41;
+    SettingProto accessibility_captioning_locale = 42;
+    SettingProto accessibility_captioning_preset = 43;
+    SettingProto accessibility_captioning_background_color = 44;
+    SettingProto accessibility_captioning_foreground_color = 45;
+    SettingProto accessibility_captioning_edge_type = 46;
+    SettingProto accessibility_captioning_edge_color = 47;
+    SettingProto accessibility_captioning_window_color = 48;
+    SettingProto accessibility_captioning_typeface = 49;
+    SettingProto accessibility_captioning_font_scale = 50;
+    SettingProto accessibility_display_inversion_enabled = 51;
+    SettingProto accessibility_display_daltonizer_enabled = 52;
+    SettingProto accessibility_display_daltonizer = 53;
+    SettingProto accessibility_autoclick_enabled = 54;
+    SettingProto accessibility_autoclick_delay = 55;
+    SettingProto accessibility_large_pointer_icon = 56;
+    SettingProto long_press_timeout = 57;
+    SettingProto multi_press_timeout = 58;
+    SettingProto enabled_print_services = 59;
+    SettingProto disabled_print_services = 60;
+    SettingProto display_density_forced = 61;
+    SettingProto tts_default_rate = 62;
+    SettingProto tts_default_pitch = 63;
+    SettingProto tts_default_synth = 64;
+    SettingProto tts_default_locale = 65;
+    SettingProto tts_enabled_plugins = 66;
+    SettingProto connectivity_release_pending_intent_delay_ms = 67;
+    SettingProto allowed_geolocation_origins = 68;
+    SettingProto preferred_tty_mode = 69;
+    SettingProto enhanced_voice_privacy_enabled = 70;
+    SettingProto tty_mode_enabled = 71;
+    SettingProto backup_enabled = 72;
+    SettingProto backup_auto_restore = 73;
+    SettingProto backup_provisioned = 74;
+    SettingProto backup_transport = 75;
+    SettingProto last_setup_shown = 76;
+    SettingProto search_global_search_activity = 77;
+    SettingProto search_num_promoted_sources = 78;
+    SettingProto search_max_results_to_display = 79;
+    SettingProto search_max_results_per_source = 80;
+    SettingProto search_web_results_override_limit = 81;
+    SettingProto search_promoted_source_deadline_millis = 82;
+    SettingProto search_source_timeout_millis = 83;
+    SettingProto search_prefill_millis = 84;
+    SettingProto search_max_stat_age_millis = 85;
+    SettingProto search_max_source_event_age_millis = 86;
+    SettingProto search_min_impressions_for_source_ranking = 87;
+    SettingProto search_min_clicks_for_source_ranking = 88;
+    SettingProto search_max_shortcuts_returned = 89;
+    SettingProto search_query_thread_core_pool_size = 90;
+    SettingProto search_query_thread_max_pool_size = 91;
+    SettingProto search_shortcut_refresh_core_pool_size = 92;
+    SettingProto search_shortcut_refresh_max_pool_size = 93;
+    SettingProto search_thread_keepalive_seconds = 94;
+    SettingProto search_per_source_concurrent_query_limit = 95;
+    SettingProto mount_play_notification_snd = 96;
+    SettingProto mount_ums_autostart = 97;
+    SettingProto mount_ums_prompt = 98;
+    SettingProto mount_ums_notify_enabled = 99;
+    SettingProto anr_show_background = 100;
+    SettingProto voice_recognition_service = 101;
+    SettingProto package_verifier_user_consent = 102;
+    SettingProto selected_spell_checker = 103;
+    SettingProto selected_spell_checker_subtype = 104;
+    SettingProto spell_checker_enabled = 105;
+    SettingProto incall_power_button_behavior = 106;
+    SettingProto incall_back_button_behavior = 107;
+    SettingProto wake_gesture_enabled = 108;
+    SettingProto doze_enabled = 109;
+    SettingProto doze_always_on = 110;
+    SettingProto doze_pulse_on_pick_up = 111;
+    SettingProto doze_pulse_on_double_tap = 112;
+    SettingProto ui_night_mode = 113;
+    SettingProto screensaver_enabled = 114;
+    SettingProto screensaver_components = 115;
+    SettingProto screensaver_activate_on_dock = 116;
+    SettingProto screensaver_activate_on_sleep = 117;
+    SettingProto screensaver_default_component = 118;
+    SettingProto nfc_payment_default_component = 119;
+    SettingProto nfc_payment_foreground = 120;
+    SettingProto sms_default_application = 121;
+    SettingProto dialer_default_application = 122;
+    SettingProto emergency_assistance_application = 123;
+    SettingProto assist_structure_enabled = 124;
+    SettingProto assist_screenshot_enabled = 125;
+    SettingProto assist_disclosure_enabled = 126;
+    SettingProto enabled_notification_assistant = 127;
+    SettingProto enabled_notification_listeners = 128;
+    SettingProto enabled_notification_policy_access_packages = 129;
+    SettingProto sync_parent_sounds = 130;
+    SettingProto immersive_mode_confirmations = 131;
+    SettingProto print_service_search_uri = 132;
+    SettingProto payment_service_search_uri = 133;
+    SettingProto skip_first_use_hints = 134;
+    SettingProto unsafe_volume_music_active_ms = 135;
+    SettingProto lock_screen_show_notifications = 136;
+    SettingProto tv_input_hidden_inputs = 137;
+    SettingProto tv_input_custom_labels = 138;
+    SettingProto usb_audio_automatic_routing_disabled = 139;
+    SettingProto sleep_timeout = 140;
+    SettingProto double_tap_to_wake = 141;
+    SettingProto assistant = 142;
+    SettingProto camera_gesture_disabled = 143;
+    SettingProto camera_double_tap_power_gesture_disabled = 144;
+    SettingProto camera_double_twist_to_flip_enabled = 145;
+    SettingProto night_display_activated = 146;
+    SettingProto night_display_auto_mode = 147;
+    SettingProto night_display_custom_start_time = 148;
+    SettingProto night_display_custom_end_time = 149;
+    SettingProto brightness_use_twilight = 150;
+    SettingProto enabled_vr_listeners = 151;
+    SettingProto vr_display_mode = 152;
+    SettingProto carrier_apps_handled = 153;
+    SettingProto managed_profile_contact_remote_search = 154;
+    SettingProto automatic_storage_manager_enabled = 155;
+    SettingProto automatic_storage_manager_days_to_retain = 156;
+    SettingProto automatic_storage_manager_bytes_cleared = 157;
+    SettingProto automatic_storage_manager_last_run = 158;
+    SettingProto system_navigation_keys_enabled = 159;
+    SettingProto downloads_backup_enabled = 160;
+    SettingProto downloads_backup_allow_metered = 161;
+    SettingProto downloads_backup_charging_only = 162;
+    SettingProto automatic_storage_manager_downloads_days_to_retain = 163;
+    SettingProto qs_tiles = 164;
+    SettingProto demo_user_setup_complete = 165;
+    SettingProto web_action_enabled = 166;
+    SettingProto device_paired = 167;
+}
+
+message SystemSettingsProto {
+    // Historical operations
+    repeated SettingsOperationProto historical_op = 1;
+
+    SettingProto end_button_behavior = 2;
+    SettingProto advanced_settings = 3;
+    SettingProto bluetooth_discoverability = 4;
+    SettingProto bluetooth_discoverability_timeout = 5;
+    SettingProto font_scale = 6;
+    SettingProto system_locales = 7;
+    SettingProto screen_off_timeout = 8;
+    SettingProto screen_brightness = 9;
+    SettingProto screen_brightness_for_vr = 10;
+    SettingProto screen_brightness_mode = 11;
+    SettingProto screen_auto_brightness_adj = 12;
+    SettingProto mode_ringer_streams_affected = 13;
+    SettingProto mute_streams_affected = 14;
+    SettingProto vibrate_on = 15;
+    SettingProto vibrate_input_devices = 16;
+    SettingProto volume_ring = 17;
+    SettingProto volume_system = 18;
+    SettingProto volume_voice = 19;
+    SettingProto volume_music = 20;
+    SettingProto volume_alarm = 21;
+    SettingProto volume_notification = 22;
+    SettingProto volume_bluetooth_sco = 23;
+    SettingProto volume_master = 24;
+    SettingProto master_mono = 25;
+    SettingProto vibrate_in_silent = 26;
+    SettingProto append_for_last_audible = 27;
+    SettingProto ringtone = 28;
+    SettingProto ringtone_cache = 29;
+    SettingProto notification_sound = 30;
+    SettingProto notification_sound_cache = 31;
+    SettingProto alarm_alert = 32;
+    SettingProto alarm_alert_cache = 33;
+    SettingProto media_button_receiver = 34;
+    SettingProto text_auto_replace = 35;
+    SettingProto text_auto_caps = 36;
+    SettingProto text_auto_punctuate = 37;
+    SettingProto text_show_password = 38;
+    SettingProto show_gtalk_service_status = 39;
+    SettingProto time_12_24 = 40;
+    SettingProto date_format = 41;
+    SettingProto setup_wizard_has_run = 42;
+    SettingProto accelerometer_rotation = 43;
+    SettingProto user_rotation = 44;
+    SettingProto hide_rotation_lock_toggle_for_accessibility = 45;
+    SettingProto vibrate_when_ringing = 46;
+    SettingProto dtmf_tone_when_dialing = 47;
+    SettingProto dtmf_tone_type_when_dialing = 48;
+    SettingProto hearing_aid = 49;
+    SettingProto tty_mode = 50;
+    SettingProto sound_effects_enabled = 51;
+    SettingProto haptic_feedback_enabled = 52;
+    SettingProto notification_light_pulse = 53;
+    SettingProto pointer_location = 54;
+    SettingProto show_touches = 55;
+    SettingProto window_orientation_listener_log = 56;
+    SettingProto lockscreen_sounds_enabled = 57;
+    SettingProto lockscreen_disabled = 58;
+    SettingProto sip_receive_calls = 59;
+    SettingProto sip_call_options = 60;
+    SettingProto sip_always = 61;
+    SettingProto sip_address_only = 62;
+    SettingProto pointer_speed = 63;
+    SettingProto lock_to_app_enabled = 64;
+    SettingProto egg_mode = 65;
+    SettingProto when_to_make_wifi_calls = 66;
+}
+
+message SettingProto {
+    // ID of the setting
+    string id = 1;
+
+    // Name of the setting
+    string name = 2;
+
+    // Package name of the setting
+    string pkg = 3;
+
+    // Value of this setting
+    string value = 4;
+
+    // Default value of this setting
+    string default_value = 5;
+
+    // Whether the default is set by the system
+    bool default_from_system = 6;
+}
+
+message SettingsOperationProto {
+    // When the operation happened
+    int64 timestamp = 1;
+
+    // Type of the operation
+    string operation = 2;
+
+    // Name of the setting that was affected (optional)
+    string setting = 3;
+}
diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto
new file mode 100644
index 0000000..4d86526
--- /dev/null
+++ b/core/proto/android/service/diskstats.proto
@@ -0,0 +1,94 @@
+/*
+ * 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.diskstats;
+
+option java_multiple_files = true;
+option java_outer_classname = "DiskStatsServiceProto";
+
+message DiskStatsServiceDumpProto {
+    enum EncryptionType {
+        // Unknown encryption type
+        ENCRYPTION_UNKNOWN = 0;
+        // No encryption
+        ENCRYPTION_NONE = 1;
+        // Full disk encryption
+        ENCRYPTION_FULL_DISK = 2;
+        // File-based encryption
+        ENCRYPTION_FILE_BASED = 3;
+    }
+    // Whether the latency test resulted in an error
+    bool has_test_error = 1;
+    // If the test errored, error message is contained here
+    string error_message = 2;
+    // 512B write latency in milliseconds, if the test was successful
+    int32 write_512b_latency_millis = 3;
+    // Free Space in the major partitions
+    repeated DiskStatsFreeSpaceProto partitions_free_space = 4;
+    // Is the device using file-based encryption, full disk encryption or other
+    EncryptionType encryption = 5;
+    // Cached values of folder sizes, etc.
+    DiskStatsCachedValuesProto cached_folder_sizes = 6;
+}
+
+message DiskStatsCachedValuesProto {
+    // Total app data size, in kilobytes
+    int64 agg_apps_size = 1;
+    // Total app cache size, in kilobytes
+    int64 agg_apps_cache_size = 2;
+    // Size of image files, in kilobytes
+    int64 photos_size = 3;
+    // Size of video files, in kilobytes
+    int64 videos_size = 4;
+    // Size of audio files, in kilobytes
+    int64 audio_size = 5;
+    // Size of downloads, in kilobytes
+    int64 downloads_size = 6;
+    // Size of system directory, in kilobytes
+    int64 system_size = 7;
+    // Size of other files, in kilobytes
+    int64 other_size = 8;
+    // Sizes of individual packages
+    repeated DiskStatsAppSizesProto app_sizes = 9;
+}
+
+message DiskStatsAppSizesProto {
+    // Name of the package
+    string package_name = 1;
+    // App's data size in kilobytes
+    int64 app_size = 2;
+    // App's cache size in kilobytes
+    int64 cache_size = 3;
+}
+
+message DiskStatsFreeSpaceProto {
+    enum Folder {
+        // Data folder
+        FOLDER_DATA = 0;
+        // Cache folder
+        FOLDER_CACHE = 1;
+        // System folder
+        FOLDER_SYSTEM = 2;
+    }
+    // Which folder?
+    Folder folder = 1;
+    // Available space, in kilobytes
+    int64 available_space = 2;
+    // Total space, in kilobytes
+    int64 total_space = 3;
+}
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
new file mode 100644
index 0000000..5cca6ab
--- /dev/null
+++ b/core/proto/android/service/netstats.proto
@@ -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.
+ */
+
+syntax = "proto3";
+
+package android.service;
+
+option java_multiple_files = true;
+option java_outer_classname = "NetworkStatsServiceProto";
+
+// Represents dumpsys from NetworkStatsService (netstats).
+message NetworkStatsServiceDumpProto {
+    repeated NetworkInterfaceProto active_interfaces = 1;
+
+    repeated NetworkInterfaceProto active_uid_interfaces = 2;
+
+    NetworkStatsRecorderProto dev_stats = 3;
+
+    NetworkStatsRecorderProto xt_stats = 4;
+
+    NetworkStatsRecorderProto uid_stats = 5;
+
+    NetworkStatsRecorderProto uid_tag_stats = 6;
+}
+
+// Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
+message NetworkInterfaceProto {
+    string interface = 1;
+
+    NetworkIdentitySetProto identities = 2;
+}
+
+// Corresponds to NetworkIdentitySet.
+message NetworkIdentitySetProto {
+    repeated NetworkIdentityProto identities = 1;
+}
+
+// Corresponds to NetworkIdentity.
+message NetworkIdentityProto {
+    // Constats from ConnectivityManager.TYPE_*.
+    int32 type = 1;
+
+    string subscriber_id = 2;
+
+    string network_id = 3;
+
+    bool roaming = 4;
+
+    bool metered = 5;
+}
+
+// Corresponds to NetworkStatsRecorder.
+message NetworkStatsRecorderProto {
+    int64 pending_total_bytes = 1;
+
+    NetworkStatsCollectionProto complete_history = 2;
+}
+
+// Corresponds to NetworkStatsCollection.
+message NetworkStatsCollectionProto {
+    repeated NetworkStatsCollectionStatsProto stats = 1;
+}
+
+// Corresponds to NetworkStatsCollection.mStats.
+message NetworkStatsCollectionStatsProto {
+    NetworkStatsCollectionKeyProto key = 1;
+
+    NetworkStatsHistoryProto history = 2;
+}
+
+// Corresponds to NetworkStatsCollection.Key.
+message NetworkStatsCollectionKeyProto {
+    NetworkIdentitySetProto identity = 1;
+
+    int32 uid = 2;
+
+    int32 set = 3;
+
+    int32 tag = 4;
+}
+
+// Corresponds to NetworkStatsHistory.
+message NetworkStatsHistoryProto {
+    // Duration for this bucket in milliseconds.
+    int64 bucket_duration_ms = 1;
+
+    repeated NetworkStatsHistoryBucketProto buckets = 2;
+}
+
+// Corresponds to each bucket in NetworkStatsHistory.
+message NetworkStatsHistoryBucketProto {
+    // Bucket start time in milliseconds since epoch.
+    int64 bucket_start_ms = 1;
+
+    int64 rx_bytes = 2;
+
+    int64 rx_packets = 3;
+
+    int64 tx_bytes = 4;
+
+    int64 tx_packets = 5;
+
+    int64 operations = 6;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 84b03d2..6d48862 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -801,6 +801,16 @@
         android:description="@string/permdesc_callPhone"
         android:protectionLevel="dangerous" />
 
+    <!-- Allows an application to manage its own calls, but rely on the system to route focus to the
+         currently active call.
+        <p>Protection level: dangerous
+    -->
+    <permission android:name="android.permission.MANAGE_OWN_CALLS"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_manageOwnCalls"
+        android:description="@string/permdesc_manageOwnCalls"
+        android:protectionLevel="dangerous" />
+
     <!-- Allows an application to access the IMS call service: making and
          modifying a call
         <p>Protection level: signature|privileged
@@ -1259,7 +1269,7 @@
          recommendations and scores from the NetworkScoreService.
          <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|setup" />
 
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
@@ -1953,7 +1963,7 @@
          {@link android.content.pm.PackageManager#addPackageToPreferred}
          for details. -->
     <permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|verifier" />
 
     <!-- Allows an application to receive the
          {@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
@@ -2470,13 +2480,23 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to request installing packages. Apps
-         targeting APIs greater than 22 must hold this permission in
+         targeting APIs greater than 25 must hold this permission in
          order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
         android:label="@string/permlab_requestInstallPackages"
         android:description="@string/permdesc_requestInstallPackages"
+        android:protectionLevel="signature|appop" />
+
+    <!-- Allows an application to request deleting packages. Apps
+         targeting APIs greater than 25 must hold this permission in
+         order to use {@link android.content.Intent#ACTION_UNINSTALL_PACKAGE}.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.permission.REQUEST_DELETE_PACKAGES"
+        android:label="@string/permlab_requestDeletePackages"
+        android:description="@string/permdesc_requestDeletePackages"
         android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to install packages.
@@ -3117,7 +3137,7 @@
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
 
 
-    <!-- Allows the holder to access the ephemeral applications on the device.
+    <!-- Allows the holder to access the instant applications on the device.
     @hide -->
     <permission android:name="android.permission.ACCESS_EPHEMERAL_APPS"
             android:protectionLevel="signature" />
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml b/core/res/res/color/text_color_primary.xml
similarity index 61%
copy from packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
copy to core/res/res/color/text_color_primary.xml
index 387ca29..831a9c4 100644
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
+++ b/core/res/res/color/text_color_primary.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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,11 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+        android:alpha="?attr/disabledAlpha"
+        android:color="?attr/colorForeground"/>
+    <item android:alpha="?attr/primaryContentAlpha"
+        android:color="?attr/colorForeground"/>
+</selector>
diff --git a/core/res/res/layout/preference_widget_seekbar.xml b/core/res/res/layout/preference_widget_seekbar.xml
index 05daa1a..0c6dbf1 100644
--- a/core/res/res/layout/preference_widget_seekbar.xml
+++ b/core/res/res/layout/preference_widget_seekbar.xml
@@ -50,7 +50,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceLarge"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
 
diff --git a/core/res/res/layout/preference_widget_seekbar_material.xml b/core/res/res/layout/preference_widget_seekbar_material.xml
index f70a472..6c72c9e 100644
--- a/core/res/res/layout/preference_widget_seekbar_material.xml
+++ b/core/res/res/layout/preference_widget_seekbar_material.xml
@@ -51,7 +51,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:singleLine="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textAppearance="?android:attr/textAppearanceListItem"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
 
@@ -60,7 +60,7 @@
             android:layout_height="wrap_content"
             android:layout_below="@android:id/title"
             android:layout_alignStart="@android:id/title"
-            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
             android:textColor="?android:attr/textColorSecondary"
             android:maxLines="4" />
 
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index cc64bb3..c004243 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Het <xliff:g id="LABEL">%1$s</xliff:g> gedeaktiveer"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferensie-oproep"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Nutswenk"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 953d3da..24feab7 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_toast" msgid="7693684144593484">"ይህን ማያ ገጽ ለመንቀል ተመለስ እና አጠቃላ እይታን ተጭነው ይያዙ።"</string>
+    <string name="lock_to_app_toast" msgid="7693684144593484">"ይህን ማያ ገጽ ለመንቀል ተመለስ እና አጠቃላይ እይታን ተጭነው ይያዙ።"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"መተግበሪያ ተሰክቷል፦ በዚህ መሣሪያ ላይ ማላቀቅ አይፈቀድም።"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ማያ ገጽ ተነቅሏል"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ተሰናክሏል"</string>
     <string name="conference_call" msgid="3751093130790472426">"የስብሰባ ጥሪ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"የመሣሪያ ጥቆማ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 1a8dc8e..f28d044c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1795,4 +1795,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"تم تعطيل <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"مكالمة جماعية"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"تلميح"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 36377e6..9b55a55 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiv edildi"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konfrans Zəngi"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <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 80d81fc..b0c62e9 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Vidžet <xliff:g id="LABEL">%1$s</xliff:g> je onemogućen"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Objašnjenje"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index e5f42c4..50cfa82 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Адключаны <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Канферэнц-выклік"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Падказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 05b8412..4b39129 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>: Деактивирано"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конферентно обаждане"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Подсказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index dbe7938..b6f7a12 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"অক্ষম করা <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"কনফারেন্স কল"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"টুলটিপ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c4a3b8f..71c9f7d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1704,4 +1704,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Onemogućen <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Savjet za alat"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 671f5d4..4db3b71 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> s\'ha desactivat"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferència"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Descripció emergent"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index fa5b13e..b72ef8b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – zakázáno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenční hovor"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Popisek"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index be50bcb..ad01840 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – deaktiveret"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonmøde"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Værktøjstip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3f64c9b..db19e193 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiviert"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonkonferenz"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Kurzinfo"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 21d42d9..333adaa 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Απενεργοποιημένο <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Κλήση συνδιάσκεψης"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Επεξήγηση εργαλείου"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 531a5ab..91b1620 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 531a5ab..91b1620 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 531a5ab..91b1620 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f888bd1..7db3b4c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Se inhabilitó <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Información sobre la herramienta"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6d88d6f..39ca2ef 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> inhabilitado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Descripción emergente"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 01edc01..2ccc3eb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Keelatud <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konverentskõne"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tööriistavihje"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3bb4492..c131c42 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desgaituta dago"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferentzia-deia"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Aholkua"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cb2f57e..d6ef85a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> غیرفعال شد"</string>
     <string name="conference_call" msgid="3751093130790472426">"تماس کنفرانسی"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"نکته‌ابزار"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a02017a..943b8e7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ei ole käytössä."</string>
     <string name="conference_call" msgid="3751093130790472426">"Puhelinneuvottelu"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Työkaluvinkki"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index b864e2b..3deefd3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
     <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
-    <string name="lock_to_app_toast" msgid="7693684144593484">"Pour annuler l\'épinglage de cet écran, maintenez enfoncée les touches Retour et Aperçu."</string>
+    <string name="lock_to_app_toast" msgid="7693684144593484">"Pour annuler l\'épinglage de cet écran, maintenez enfoncées les touches Retour et Aperçu."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'application est épinglée : l\'annulation de l\'épinglage n\'est pas autorisée sur cet appareil."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Désactivé : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Infobulle"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index cd10d36..7abb654 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Élément \"<xliff:g id="LABEL">%1$s</xliff:g>\" désactivé"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Info-bulle"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index bcf19d9..9b0f666 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -21,7 +21,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="byteShort" msgid="8340973892742019101">"B"</string>
-    <string name="kilobyteShort" msgid="7542884022844556968">"KB"</string>
+    <string name="kilobyteShort" msgid="7542884022844556968">"kB"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
     <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
     <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Desactivouse <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia telefónica"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Cadro de información"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index a79d53c..db02286 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> અક્ષમ કર્યું"</string>
     <string name="conference_call" msgid="3751093130790472426">"કોન્ફરન્સ કૉલ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ટૂલટિપ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 26a0dcc..29ead1d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"अक्षम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"कॉन्फ़्रेंस कॉल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 683a1a3..8e3ed1c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogućeno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Opis"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3c8e390..f58f365 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"A(z) <xliff:g id="LABEL">%1$s</xliff:g> letiltva"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenciahívás"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Elemleírás"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 91cdfa4..c1702c0 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Անջատած <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Կոնֆերանս զանգ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Հուշակ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 58447fa..05560d3 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferensi Telepon"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Keterangan alat"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0178b77..573d014 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Slökkt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Símafundur"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Ábending"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9228b33..74adcca 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
     <string name="conference_call" msgid="3751093130790472426">"Audioconferenza"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Descrizione comando"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f9e4b34..54c3702 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> הושבת"</string>
     <string name="conference_call" msgid="3751093130790472426">"שיחת ועידה"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"הסבר קצר"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 46c7877..47b0325 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"停止済みの「<xliff:g id="LABEL">%1$s</xliff:g>」"</string>
     <string name="conference_call" msgid="3751093130790472426">"グループ通話"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ツールチップ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7774c66..fb90136 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"გათიშული <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"საკონფერენციო ზარი"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"მინიშნება"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d15b017..377f0c9 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өшірулі"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференциялық қоңырау"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Қалқыма сөзкөмек"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 549bff2..756465c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1673,4 +1673,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ដែលបានបិទដំណើរការ"</string>
     <string name="conference_call" msgid="3751093130790472426">"ការហៅជាក្រុម"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ផ្ទាំងលោត"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 163d922..8c8ab2f 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="conference_call" msgid="3751093130790472426">"ಕಾನ್ಫರೆನ್ಸ್ ಕರೆ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ಟೂಲ್‌ಟಿಪ್"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a943f53..f0a214e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> 사용 중지됨"</string>
     <string name="conference_call" msgid="3751093130790472426">"다자간 통화"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"도움말"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index cdbb17f..f0f1ef8 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өчүрүлдү"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференц чалуу"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Калкып чыгуучу кеңеш"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 1b8a7a2..0649961 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ປິດການນຳໃຊ້ <xliff:g id="LABEL">%1$s</xliff:g> ແລ້ວ"</string>
     <string name="conference_call" msgid="3751093130790472426">"ການປະຊຸມສາຍ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ຄຳອະທິບາຍເຄື່ອງມື"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 1bcb8ca..bd694dd 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1665,7 +1665,7 @@
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Sutraukti"</string>
     <string name="zen_mode_feature_name" msgid="5254089399895895004">"Netrukdyti"</string>
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Prastova"</string>
-    <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Savaitgalio vakarą"</string>
+    <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Darbo dienos vakarą"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Savaitgalį"</string>
     <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Įvykis"</string>
     <string name="muted_by" msgid="6147073845094180001">"Nutildė <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Išj. valdiklis „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencinis skambutis"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Patarimas"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0df18d1..d17846f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> atspējots"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferences zvans"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Rīka padoms"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a4912c3..7d2ba9d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1673,4 +1673,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Оневозможен <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференциски повик"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Совет за алатка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 202e69a..c0be3a4 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="conference_call" msgid="3751093130790472426">"കോൺഫറൻസ് കോൾ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ടൂൾ ടിപ്പ്"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 1dfb039..9078460 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1669,4 +1669,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>-г цуцалсан"</string>
     <string name="conference_call" msgid="3751093130790472426">"Хурлын дуудлага"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Зөвлөмж"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4f4275a..e455178 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_toast" msgid="7693684144593484">"ही स्क्रीन अनपिन करण्यासाठी, परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
+    <string name="lock_to_app_toast" msgid="7693684144593484">"ही स्क्रीन अनपिन करण्यासाठी, परत जा आणि विहंगावलोकन करा स्पर्श करा आणि धरून ठेवा."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"अॅप पिन केलेला आहे: या डिव्हाइसवर अनपिन करण्यास अनुमती नाही."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन केली"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> अक्षम केले"</string>
     <string name="conference_call" msgid="3751093130790472426">"परिषद कॉल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 69808069..d41ff77 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dilumpuhkan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Panggilan Sidang"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Keterangan item"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index bada9a9..291d92d 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ပိတ်ထားသည့် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"လူအမြောက်အမြားတပြိုင်နက် ခေါ်ဆိုမှု"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"အကြံပြုချက်ပြ ပေါ့အပ် ဝင်းဒိုး"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d83e61e..70a8828 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> er slått av"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferansesamtale"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Verktøytips"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index a033cba..0653ab7 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1677,4 +1677,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> लाई असक्षम गरियो"</string>
     <string name="conference_call" msgid="3751093130790472426">"सम्मेलन कल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"उपकरणको वर्णन"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b6e2426..2e55648 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonische vergadering"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Knopinfo"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 21aeb9d..cff0ddb 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"ਕਾਨਫਰੰਸ ਕਾਲ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ਟੂਲਟਿਪ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 57d64ad..45b48f9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Wyłączono: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Połączenie konferencyjne"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Etykietka"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 094b30b..8b50b0f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Dica"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c0a73a0..736d6e0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferência"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Sugestão"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 094b30b..8b50b0f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Dica"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e809e3b..43b8f1f 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> a fost dezactivat"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferință telefonică"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Balon explicativ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 44b4c51..cd6c871 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виджет <xliff:g id="LABEL">%1$s</xliff:g> отключен"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференц-связь"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Подсказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 2e49ec2..031d9d0 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1673,4 +1673,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"අබල කළ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"සම්මන්ත්‍රණ ඇමතුම"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"මෙවලම් ඉඟිය"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 71a0373..e483d39 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Deaktivovaná miniaplikácia <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenčný hovor"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Popis"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index fbd2fc2..b74875a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogočeno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenčni klic"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Opis orodja"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 51c4b94..536c60f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> u çaktivizua"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonatë konferencë"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Këshilla për veglën"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c23044c..c7d8fdf 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виџет <xliff:g id="LABEL">%1$s</xliff:g> је онемогућен"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференцијски позив"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Објашњење"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index adfd909..f5e3445 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> har inaktiverats"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenssamtal"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Beskrivning"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d460fe0..1c91e99 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1669,4 +1669,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> imezimwa"</string>
     <string name="conference_call" msgid="3751093130790472426">"Simu ya Kongamano"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Kidirisha cha vidokezo"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 96a9f48..b04f928 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"முடக்கப்பட்டது: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"குழு அழைப்பு"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"உதவிக்குறிப்பு"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4b93693..7f2ffdd 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> నిలిపివేయబడింది"</string>
     <string name="conference_call" msgid="3751093130790472426">"కాన్ఫరెన్స్ కాల్"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"సాధనం చిట్కా"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a46935c..7e2f78c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ปิดใช้ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"การประชุมสาย"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"เคล็ดลับเครื่องมือ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b738ada..f245774 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Na-disable ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index dea294a..0c3db29 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> devre dışı"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferans Çağrısı"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"İpucu"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 842d06f..19e3798 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> вимкнено"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференц-виклик"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Спливаюча підказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index bb7a69e..3eb2025 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"غیر فعال کردہ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"کانفرنس کال"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ٹول ٹپ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d8b8e7e..c706816 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> vidjeti o‘chirilgan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferens-aloqa"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Maslahat oynasi"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9d204c2..a406656 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Đã tắt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Cuộc gọi nhiều bên"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Chú giải công cụ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6f51494..55773c6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"电话会议"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"提示"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a4723db..300cc36 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"「<xliff:g id="LABEL">%1$s</xliff:g>」已停用"</string>
     <string name="conference_call" msgid="3751093130790472426">"會議通話"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"提示"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dd37549..ffa10d7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"電話會議"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"工具提示"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9cb03b8..a5da794 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhutshaziwe"</string>
     <string name="conference_call" msgid="3751093130790472426">"Ikholi yengqungquthela"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Ithulithiphu"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dd33718..df7a5f5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -62,6 +62,8 @@
 
         <!-- Default disabled alpha for widgets that set enabled/disabled alpha programmatically. -->
         <attr name="disabledAlpha" format="float" />
+        <!-- The alpha applied to the foreground color to create the primary text color. -->
+        <attr name="primaryContentAlpha" format="float" />
         <!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
         <attr name="backgroundDimAmount" format="float" />
         <!-- Control whether dimming behind the window is enabled.  The default
@@ -2888,15 +2890,13 @@
         <attr name="forceHasOverlappingRendering" format="boolean" />
 
         <!-- Defines text displayed in a small popup window on hover or long press. -->
-        <attr name="tooltip" format="string" localization="suggested" />
+        <attr name="tooltipText" format="string" localization="suggested" />
 
         <!-- Whether this view is a root of a keyboard navigation cluster.
              See {@link android.view.View#setKeyboardNavigationCluster(boolean)}. -->
         <attr name="keyboardNavigationCluster" format="boolean" />
 
-        <!-- Whether this view is a root of a keyboard navigation section.
-             See {@link android.view.View#setKeyboardNavigationSection(boolean)}. -->
-        <attr name="keyboardNavigationSection" format="boolean" />
+        <attr name="__removed0" format="boolean" />
 
         <!-- Defines the next keyboard navigation cluster.
 
@@ -2905,12 +2905,7 @@
              will result when the reference is accessed.-->
         <attr name="nextClusterForward" format="reference"/>
 
-        <!-- Defines the next keyboard navigation section.
-
-             If the reference refers to a view that does not exist or is part
-             of a hierarchy that is invisible, a {@link java.lang.RuntimeException}
-             will result when the reference is accessed.-->
-        <attr name="nextSectionForward" format="reference"/>
+        <attr name="__removed1" format="reference"/>
 
         <!-- Whether this view is a default-focus view.
              Only one view per keyboard navigation cluster can have this attribute set to true.
@@ -4705,7 +4700,8 @@
             screens with limited space for text. -->
             <enum name="full" value="2" />
         </attr>
-        <!-- Specify the type of auto-size. -->
+        <!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
+        works only for TextView -->
         <attr name="autoSizeText" format="enum">
             <!-- No auto-sizing (default). -->
             <enum name="none" value="0" />
@@ -7027,7 +7023,7 @@
         <attr name="contentDescription" format="string" />
 
         <!-- The tooltip text associated with the item. -->
-        <attr name="tooltip" format="string" />
+        <attr name="tooltipText" format="string" />
 
     </declare-styleable>
 
@@ -7615,6 +7611,21 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- AutoFill attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a
+         {@link android.service.autofill.AutoFillService}, which is referenced from its
+         {@link android.service.autofill#SERVICE_META_DATA} meta-data entry.
+    -->
+    <declare-styleable name="AutoFillService">
+        <!-- Fully qualified class name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity" />
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- Contacts meta-data attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -8428,7 +8439,7 @@
     <!-- @hide Attributes which will be read by the Activity to intialize the
                base activity TaskDescription. -->
     <declare-styleable name="ActivityTaskDescription">
-        <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary 
+        <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary
                    color. -->
         <attr name="colorPrimary" />
         <!-- @hide From Theme.colorBackground, used for the TaskDescription background
@@ -8459,4 +8470,14 @@
         <attr name="font" format="reference" />
         <attr name="fontWeight" format="integer" />
     </declare-styleable>
+
+    <!-- @hide -->
+    <declare-styleable name="RecyclerView">
+        <attr name="layoutManager" format="string" />
+        <attr name="orientation" />
+        <attr name="descendantFocusability" />
+        <attr name="spanCount" format="integer"/>
+        <attr name="reverseLayout" format="boolean" />
+        <attr name="stackFromEnd" format="boolean" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b961394..5235116 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -776,6 +776,21 @@
         <enum name="locked" value="14" />
     </attr>
 
+    <!-- Specify the configuration changes that trigger the system to restart the
+         current activity if any of these configuration changes happen in the system.
+         The valid configuration changes include mcc and mnc which are the same with
+         those in configChanges. By default from Android O, we don't restart the activity
+         even the app doesn't specify mcc or mnc in configChanges. If the app wants to
+         restart, specify them in restartOnConfigChanges. -->
+    <attr name="restartOnConfigChanges">
+        <!-- The IMSI MCC has changed, that is a SIM has been detected and
+             updated the Mobile Country Code. -->
+        <flag name="mcc" value="0x0001" />
+        <!-- The IMSI MNC has changed, that is a SIM has been detected and
+             updated the Mobile Network Code. -->
+        <flag name="mnc" value="0x0002" />
+    </attr>
+
     <!-- Specify one or more configuration changes that the activity will
          handle itself.  If not specified, the activity will be restarted
          if any of these configuration changes happen in the system.  Otherwise,
@@ -793,10 +808,16 @@
          include/utils/ResourceTypes.h. -->
     <attr name="configChanges">
         <!-- The IMSI MCC has changed, that is a SIM has been detected and
-             updated the Mobile Country Code. -->
+             updated the Mobile Country Code. By default from Android O, we
+             don't restart the activity even the app doesn't specify mcc in
+             configChanges. If the app wants to restart, specify mcc in
+             restartOnConfigChanges. -->
         <flag name="mcc" value="0x0001" />
         <!-- The IMSI MNC has changed, that is a SIM has been detected and
-             updated the Mobile Network Code. -->
+             updated the Mobile Network Code. By default from Android O, we
+             don't restart the activity even the app doesn't specify mnc in
+             configChanges. If the app wants to restart, specify mnc in
+             restartOnConfigChanges. -->
         <flag name="mnc" value="0x0002" />
         <!-- The locale has changed, that is the user has selected a new
              language that text should be displayed in. -->
@@ -843,6 +864,9 @@
         <flag name="density" value="0x1000" />
         <!-- The layout direction has changed. For example going from LTR to RTL. -->
         <flag name="layoutDirection" value="0x2000" />
+        <!-- The colorimetry capabilities of the screen have changed (color gamut
+             or dynamic range). -->
+        <flag name="colorimetry" value="0x4000" />
         <!-- The font scaling factor has changed, that is the user has
              selected a new global font size. -->
         <flag name="fontScale" value="0x40000000" />
@@ -1209,9 +1233,9 @@
          -->
     <attr name="autoVerify" format="boolean" />
 
-    <!-- Specify whether a component should be visible to ephemeral apps.
+    <!-- Specify whether a component should be visible to instant apps.
          -->
-    <attr name="visibleToEphemeral" format="boolean" />
+    <attr name="visibleToInstantApps" format="boolean" />
 
     <!-- An XML resource with the application's Network Security Config. -->
     <attr name="networkSecurityConfig" format="reference" />
@@ -1597,6 +1621,27 @@
         <attr name="name" />
     </declare-styleable>
 
+
+    <!-- The <code>static-library</code> tag declares that this apk is providing itself
+       as a static shared library for other applications to use. Any app can declare such
+       a library and there can be only one static shared library per package. These libraries
+       are updatable, multiple versions can be installed at the same time, and an app links
+       against a specific version simulating static linking while allowing code sharing.
+       Other apks can link to it with the {@link #AndroidManifestUsesLibrary uses-static-library}
+       tag.
+
+     <p>This appears as a child tag of the
+     {@link #AndroidManifestApplication application} tag. -->
+    <declare-styleable name="AndroidManifestStaticLibrary" parent="AndroidManifestApplication">
+        <!-- Required public name of the library, which other components and
+        packages will use when referring to this library.  This is a string using
+        Java-style scoping to ensure it is unique.  The name should typically
+        be the same as the apk's package name. -->
+        <attr name="name" />
+        <!-- Required specific library version. -->
+        <attr name="version" />
+    </declare-styleable>
+
     <!-- The <code>uses-libraries</code> specifies a shared library that this
          package requires to be linked against.  Specifying this flag tells the
          system to include this library's code in your class loader.
@@ -1616,6 +1661,24 @@
         <attr name="required" />
     </declare-styleable>
 
+    <!-- The <code>uses-static-library</code> specifies a shared <strong>static</strong>
+         library that this package requires to be statically linked against. Specifying
+         this tag tells the system to include this library's code in your class loader.
+         Depending on a static shared library is equivalent to statically linking with
+         the library at build time while it offers apps to share code defined in such
+         libraries. Hence, static libraries are strictly required.
+
+         <p>This appears as a child tag of the
+         {@link #AndroidManifestApplication application} tag. -->
+    <declare-styleable name="AndroidManifestUsesStaticLibrary" parent="AndroidManifestApplication">
+        <!-- Required name of the library you use. -->
+        <attr name="name" />
+        <!-- Specify which version of the shared library should be statically linked. -->
+        <attr name="version" />
+        <!-- The SHA-256 digest of the library signing certificate. -->
+        <attr name="certDigest" format="string" />
+    </declare-styleable>
+
     <!-- The <code>supports-screens</code> specifies the screen dimensions an
          application supports.  By default a modern application supports all
          screen sizes and must explicitly disable certain screen sizes here;
@@ -1759,7 +1822,7 @@
         <attr name="exported" />
         <attr name="singleUser" />
         <attr name="directBootAware" />
-        <attr name="visibleToEphemeral" />
+        <attr name="visibleToInstantApps" />
     </declare-styleable>
 
     <!-- Attributes that can be supplied in an AndroidManifest.xml
@@ -1849,7 +1912,7 @@
              client to bind to the service as if it were running it its own package.  The service
              must also be {@link android.R.attr#exported} if this flag is set. -->
         <attr name="externalService" format="boolean" />
-        <attr name="visibleToEphemeral" />
+        <attr name="visibleToInstantApps" />
     </declare-styleable>
 
     <!-- The <code>receiver</code> tag declares an
@@ -1917,6 +1980,7 @@
         <attr name="launchMode" />
         <attr name="screenOrientation" />
         <attr name="configChanges" />
+        <attr name="restartOnConfigChanges" />
         <attr name="permission" />
         <attr name="multiprocess" />
         <attr name="process" />
@@ -1971,7 +2035,7 @@
              This attribute is ignored if the activity isn't a launcher. -->
         <attr name="onTopLauncher" format="boolean" />
         <attr name="rotationAnimation" />
-        <attr name="visibleToEphemeral" />
+        <attr name="visibleToInstantApps" />
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 8f0350a..e2498df7 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -20,11 +20,14 @@
     <color name="primary_device_default_dark">@color/primary_material_dark</color>
     <color name="primary_device_default_light">@color/primary_material_light</color>
     <color name="primary_device_default_settings">@color/primary_material_settings</color>
+    <color name="primary_device_default_settings_light">@color/primary_material_settings_light</color>
     <color name="primary_dark_device_default_dark">@color/primary_dark_material_dark</color>
     <color name="primary_dark_device_default_light">@color/primary_dark_material_light</color>
     <color name="primary_dark_device_default_settings">@color/primary_dark_material_settings</color>
+    <color name="primary_dark_device_default_settings_light">@color/primary_dark_material_settings_light</color>
 
     <color name="secondary_device_default_settings">@color/secondary_material_settings</color>
+    <color name="secondary_device_default_settings_light">@color/secondary_material_settings_light</color>
     <color name="tertiary_device_default_settings">@color/tertiary_material_settings</color>
     <color name="quaternary_device_default_settings">@color/quaternary_material_settings</color>
 
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 40e7341..db89c22 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -27,12 +27,15 @@
     <color name="primary_material_dark">@color/material_grey_900</color>
     <color name="primary_material_light">@color/material_grey_100</color>
     <color name="primary_material_settings">@color/material_blue_grey_900</color>
+    <color name="primary_material_settings_light">@color/material_grey_100</color>
     <color name="primary_dark_material_dark">@color/black</color>
     <color name="primary_dark_material_light">@color/material_grey_600</color>
     <color name="primary_dark_material_light_light_status_bar">@color/material_grey_300</color>
     <color name="primary_dark_material_settings">@color/material_blue_grey_950</color>
+    <color name="primary_dark_material_settings_light">@color/material_grey_300</color>
 
     <color name="secondary_material_settings">@color/material_blue_grey_800</color>
+    <color name="secondary_material_settings_light">@color/material_grey_200</color>
     <color name="tertiary_material_settings">@color/material_blue_grey_700</color>
     <color name="quaternary_material_settings">@color/material_blue_grey_200</color>
 
@@ -73,6 +76,8 @@
 
     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
+    <item name="primary_content_alpha_material_light" format="float" type="dimen">1</item>
+    <item name="primary_content_alpha_material_dark" format="float" type="dimen">0.87</item>
 
     <item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
     <item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
@@ -86,6 +91,7 @@
     <color name="material_grey_800">#ff424242</color>
     <color name="material_grey_600">#ff757575</color>
     <color name="material_grey_300">#ffe0e0e0</color>
+    <color name="material_grey_200">#ffeeeeee</color>
     <color name="material_grey_100">#fff5f5f5</color>
     <color name="material_grey_50">#fffafafa</color>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index db157bf..7de48d3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2710,4 +2710,10 @@
 
     <!-- Component name of the default cell broadcast receiver -->
     <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+
+    <!-- The component name, flattened to a string, for the default accessibility service to be
+         enabled by the accessibility shortcut. This service must be trusted, as it can be activated
+         without explicit consent of the user. If no accessibility service with the specified name
+         exists on the device, the accessibility shortcut will be disabled by default. -->
+    <string name="config_defaultAccessibilityService" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bd19521..e6358a3 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -509,4 +509,10 @@
     <dimen name="tooltip_precise_anchor_threshold">96dp</dimen>
     <!-- Extra tooltip offset used when anchoring to the mouse/touch position -->
     <dimen name="tooltip_precise_anchor_extra_offset">8dp</dimen>
+
+    <!-- The max amount of scroll ItemTouchHelper will trigger if dragged view is out of
+         RecyclerView's bounds.-->
+    <dimen name="item_touch_helper_max_drag_scroll_per_frame">20dp</dimen>
+    <dimen name="item_touch_helper_swipe_escape_velocity">120dp</dimen>
+    <dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 5547706..613616f 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -97,6 +97,7 @@
   <item type="id" name="redo" />
   <item type="id" name="replaceText" />
   <item type="id" name="shareText" />
+  <item type="id" name="textAssist" />
   <item type="id" name="selection_start_handle" />
   <item type="id" name="selection_end_handle" />
   <item type="id" name="insertion_handle" />
@@ -131,4 +132,7 @@
   <item type="id" name="cross_task_transition" />
 
   <item type="id" name="accessibilityActionClickOnClickableSpan" />
+
+  <!-- ItemTouchHelper uses this id to save a View's original elevation. -->
+  <item type="id" name="item_touch_helper_previous_elevation"/>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 064d31e..30da26b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2764,7 +2764,7 @@
         <public name="fontStyle" />
         <public name="font" />
         <public name="fontWeight" />
-        <public name="tooltip" />
+        <public name="tooltipText" />
         <public name="autoSizeText" />
         <public name="autoSizeStepGranularity" />
         <public name="autoSizeStepSizeSet" />
@@ -2775,24 +2775,29 @@
         <public name="layout_marginVertical" />
         <public name="paddingHorizontal" />
         <public name="paddingVertical" />
-        <public name="visibleToEphemeral" />
+        <public name="visibleToInstantApps" />
         <public name="keyboardNavigationCluster" />
-        <public name="keyboardNavigationSection" />
+        <public name="__removed0" />
         <public name="nextClusterForward" />
-        <public name="nextSectionForward" />
+        <public name="__removed1" />
         <public name="textColorError" />
         <public name="focusedByDefault" />
         <public name="appCategory" />
         <public name="autoSizeMaxTextSize" />
         <public name="supportsDismissingWindow" />
+        <public name="restartOnConfigChanges" />
+        <public name="certDigest" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
     </public-group>
 
     <public-group type="id" first-id="0x01020041">
+        <public name="textAssist" />
     </public-group>
 
+    <public type="attr" name="primaryContentAlpha" />
+
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 87a4732..d09b190 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -397,7 +397,7 @@
     <string name="network_logging_notification_title">Network traffic is being monitored</string>
     <!-- Content text for a notification. Tapping opens a dialog with more information on network
         logging. [CHAR LIMIT=NONE]-->
-    <string name="network_logging_notification_text">Tap for more details</string>
+    <string name="network_logging_notification_text">Tap to learn more</string>
 
     <!-- Factory reset warning dialog strings--> <skip />
     <!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] -->
@@ -1019,6 +1019,14 @@
       phone number and device IDs, whether a call is active, and the remote number
       connected by a call.</string>
 
+    <!-- Title of an application permission.  When granted the user is giving access to a third
+         party app to route its calls through the system. -->
+    <string name="permlab_manageOwnCalls">route calls through the system</string>
+    <!-- Description of an application permission.  When granted the user is giving access to a
+         third party app to route its calls through the system. -->
+    <string name="permdesc_manageOwnCalls">Allows the app to route its calls through the system in
+        order to improve the calling experience.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readPhoneNumber">read phone number</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3182,6 +3190,11 @@
     <!-- Description of an application permission that lets it read install sessions. -->
     <string name="permdesc_requestInstallPackages">Allows an application to request installation of packages.</string>
 
+    <!-- Title of an application permission that lets it read install sessions. -->
+    <string name="permlab_requestDeletePackages">request delete packages</string>
+    <!-- Description of an application permission that lets it read install sessions. -->
+    <string name="permdesc_requestDeletePackages">Allows an application to request deletion of packages.</string>
+
     <!-- Title of an application permission that lets it ask user to ignore battery optimizations for that app. -->
     <string name="permlab_requestIgnoreBatteryOptimizations">ask to ignore battery optimizations</string>
     <!-- Description of an application permission that lets it ask user to ignore battery optimizations for that app-->
@@ -3818,12 +3831,35 @@
        "Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."
     </string>
 
-    <!-- Text spoken when the user is performing a gesture that will enable accessibility. [CHAR LIMIT=none] -->
-    <string name="continue_to_enable_accessibility">Keep holding down two fingers to enable accessibility.</string>
-    <!-- Text spoken when the user enabled accessibility. [CHAR LIMIT=none] -->
-    <string name="accessibility_enabled">Accessibility enabled.</string>
-    <!-- Text spoken when the user stops preforming a gesture that would enable accessibility. [CHAR LIMIT=none] -->
-    <string name="enable_accessibility_canceled">Accessibility canceled.</string>
+    <!-- Dialog title for dialog shown when the accessibility shortcut is activated, and we want
+     to confirm that the user understands what's going to happen-->
+    <string name="accessibility_shortcut_warning_dialog_title">Accessibility Shortcut is ON</string>
+
+    <!-- Message shown in dialog when user is in the process of enabling the accessibility
+    service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
+    <string name="accessibility_shortcut_toogle_warning">
+        Turn <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> on or off by holding down
+        both volume buttons for 3 seconds.\n\nYou can change the service in
+        Settings > Accessibility.
+    </string>
+
+    <!-- Text in button that turns off the accessibility shortcut -->
+    <string name="disable_accessibility_shortcut">Turn Off Shortcut</string>
+
+    <!-- Text in button that closes the warning dialog about the accessibility shortcut, leaving the
+    shortcut enabled.-->
+    <string name="leave_accessibility_shortcut_on">Leave on</string>
+
+    <!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility
+    service.-->
+    <string name="accessibility_shortcut_enabling_service">Accessibility Shortcut turned
+        <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> on</string>
+
+    <!-- Text in toast to alert the user that the accessibility shortcut turned off an accessibility
+    service.-->
+    <string name="accessibility_shortcut_disabling_service">Accessibility Shortcut turned
+        <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> off</string>
+
     <!-- Text spoken when the current user is switched if accessibility is enabled. [CHAR LIMIT=none] -->
     <string name="user_switched">Current user <xliff:g id="name" example="Bob">%1$s</xliff:g>.</string>
     <!-- Message shown when switching to a user [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 842b575..faf451b 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1290,7 +1290,7 @@
     <style name="Widget.ActionButton.Overflow">
         <item name="src">@drawable/ic_menu_more</item>
         <item name="contentDescription">@string/action_menu_overflow_description</item>
-        <item name="tooltip">@string/action_menu_overflow_description</item>
+        <item name="tooltipText">@string/action_menu_overflow_description</item>
     </style>
 
     <style name="Widget.ActionButton.CloseMode">
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index 12b8164..dc32b26 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -660,7 +660,7 @@
         <item name="src">@drawable/ic_menu_moreoverflow_holo_dark</item>
         <item name="background">?attr/actionBarItemBackground</item>
         <item name="contentDescription">@string/action_menu_overflow_description</item>
-        <item name="tooltip">@string/action_menu_overflow_description</item>
+        <item name="tooltipText">@string/action_menu_overflow_description</item>
     </style>
 
     <style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button" />
@@ -995,7 +995,7 @@
     <style name="Widget.Holo.Light.ActionButton.Overflow">
         <item name="src">@drawable/ic_menu_moreoverflow_holo_light</item>
         <item name="contentDescription">@string/action_menu_overflow_description</item>
-        <item name="tooltip">@string/action_menu_overflow_description</item>
+        <item name="tooltipText">@string/action_menu_overflow_description</item>
     </style>
 
     <style name="Widget.Holo.Light.ActionBar.TabView" parent="Widget.Holo.ActionBar.TabView" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 709200e..0b326e9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -944,7 +944,7 @@
         <item name="src">@drawable/ic_menu_moreoverflow_material</item>
         <item name="background">?attr/actionBarItemBackground</item>
         <item name="contentDescription">@string/action_menu_overflow_description</item>
-        <item name="tooltip">@string/action_menu_overflow_description</item>
+        <item name="tooltipText">@string/action_menu_overflow_description</item>
         <item name="minWidth">@dimen/action_button_min_width_overflow_material</item>
         <item name="minHeight">@dimen/action_button_min_height_material</item>
         <item name="paddingStart">@dimen/action_bar_overflow_padding_start_material</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b923dff..6eb3bee 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1139,7 +1139,6 @@
   <java-symbol type="string" name="conference_call" />
   <java-symbol type="string" name="tooltip_popup_title" />
 
-
   <java-symbol type="plurals" name="bugreport_countdown" />
   <java-symbol type="plurals" name="last_num_days" />
   <java-symbol type="plurals" name="matches_found" />
@@ -2797,4 +2796,20 @@
 
   <java-symbol type="raw" name="fallback_categories" />
 
+  <java-symbol type="attr" name="primaryContentAlpha" />
+
+  <!-- Accessibility Shortcut -->
+  <java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
+  <java-symbol type="string" name="accessibility_shortcut_toogle_warning" />
+  <java-symbol type="string" name="accessibility_shortcut_enabling_service" />
+  <java-symbol type="string" name="accessibility_shortcut_disabling_service" />
+  <java-symbol type="string" name="disable_accessibility_shortcut" />
+  <java-symbol type="string" name="leave_accessibility_shortcut_on" />
+  <java-symbol type="string" name="config_defaultAccessibilityService" />
+
+  <!-- com.android.internal.widget.RecyclerView -->
+  <java-symbol type="id" name="item_touch_helper_previous_elevation"/>
+  <java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/>
+  <java-symbol type="dimen" name="item_touch_helper_swipe_escape_velocity"/>
+  <java-symbol type="dimen" name="item_touch_helper_swipe_escape_max_velocity"/>
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 6bd6e1c..5961cb0 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -736,20 +736,12 @@
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
     <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings">
         <!-- Color palette -->
-        <item name="colorPrimary">@color/primary_device_default_settings</item>
-        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
-        <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorPrimary">@color/primary_device_default_settings_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
+        <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
-    <!-- @hide DeviceDefault theme that should look like the Settings app. The action bar will use a
-         light background and accent color for text and icon. -->
-    <style name="Theme.DeviceDefault.Settings.LightActionBar">
-        <!-- ActionBar -->
-        <item name="actionBarTheme">@style/ThemeOverlay.DeviceDefault.ActionBar.Accent</item>
-        <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar</item>
-    </style>
-
     <!-- @hide DeviceDefault theme for a window that should use Settings theme colors
          but has a full dark palette. ONLY USED FOR QUICK SETTINGS THEME -->
     <style name="Theme.DeviceDefault.QuickSettings" parent="Theme.Material">
@@ -817,12 +809,6 @@
 
     <style name="ThemeOverlay.DeviceDefault" />
 
-    <!-- @hide Theme overlay that inherits from material actionbar,  and use accent color for
-             primary text -->
-    <style name="ThemeOverlay.DeviceDefault.ActionBar.Accent" parent="ThemeOverlay.Material.ActionBar">
-        <item name="textColorPrimary">@color/btn_colored_borderless_text_material</item>
-    </style>
-
     <style name="ThemeOverlay.DeviceDefault.Accent">
         <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 5f0ad8e..3587fec 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -48,13 +48,14 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
         <item name="disabledAlpha">@dimen/disabled_alpha_material_dark</item>
+        <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_dark</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
         <item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
@@ -413,13 +414,14 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
         <item name="disabledAlpha">@dimen/disabled_alpha_material_light</item>
+        <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_light</item>
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_light</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
         <item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
         <item name="textColorSecondary">@color/secondary_text_material_light</item>
@@ -805,7 +807,7 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_light</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
         <item name="textColorSecondary">@color/secondary_text_material_light</item>
         <item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
@@ -839,7 +841,7 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_dark</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
         <item name="textColorSecondary">@color/secondary_text_material_dark</item>
@@ -1321,10 +1323,10 @@
     </style>
 
     <!-- Default theme for Settings and activities launched from Settings. -->
-    <style name="Theme.Material.Settings" parent="Theme.Material.Light.DarkActionBar">
-        <item name="colorPrimary">@color/primary_material_settings</item>
-        <item name="colorPrimaryDark">@color/primary_dark_material_settings</item>
-        <item name="colorSecondary">@color/secondary_material_settings</item>
+    <style name="Theme.Material.Settings" parent="Theme.Material.Light.LightStatusBar">
+        <item name="colorPrimary">@color/primary_material_settings_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_material_settings_light</item>
+        <item name="colorSecondary">@color/secondary_material_settings_light</item>
 
         <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
         <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk
index 56011f7..39cf4a4 100644
--- a/core/tests/ConnectivityManagerTest/Android.mk
+++ b/core/tests/ConnectivityManagerTest/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
index cb44721..2af92df 100644
--- a/core/tests/bandwidthtests/Android.mk
+++ b/core/tests/bandwidthtests/Android.mk
@@ -23,6 +23,7 @@
 	$(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := BandwidthTests
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk
index 4a1d18c..f53419a 100644
--- a/core/tests/bluetoothtests/Android.mk
+++ b/core/tests/bluetoothtests/Android.mk
@@ -9,6 +9,7 @@
 	$(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := BluetoothTests
 LOCAL_CERTIFICATE := platform
 
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index cba485a..91ce7a4 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1168,6 +1168,7 @@
         <activity android:name="android.app.EmptyActivity">
         </activity>
         <activity android:name="com.android.internal.app.ChooserWrapperActivity"/>
+        <activity android:name="com.android.internal.app.ResolverWrapperActivity"/>
 
         <receiver android:name="android.app.activity.AbortReceiver">
             <intent-filter android:priority="1">
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
new file mode 100644
index 0000000..f60bf94
--- /dev/null
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -0,0 +1,242 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static android.os.storage.VolumeInfo.STATE_MOUNTED;
+import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;
+
+public class ApplicationPackageManagerTest extends TestCase {
+    private static final String sInternalVolPath = "/data";
+    private static final String sAdoptedVolPath = "/mnt/expand/123";
+    private static final String sPublicVolPath = "/emulated";
+    private static final String sPrivateUnmountedVolPath = "/private";
+
+    private static final String sInternalVolUuid = null; //StorageManager.UUID_PRIVATE_INTERNAL
+    private static final String sAdoptedVolUuid = "adopted";
+    private static final String sPublicVolUuid = "emulated";
+    private static final String sPrivateUnmountedVolUuid = "private";
+
+    private static final VolumeInfo sInternalVol = new VolumeInfo("private",
+            VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
+
+    private static final VolumeInfo sAdoptedVol = new VolumeInfo("adopted",
+            VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
+
+    private static final VolumeInfo sPublicVol = new VolumeInfo("public",
+            VolumeInfo.TYPE_PUBLIC, null /*DiskInfo*/, null /*partGuid*/);
+
+    private static final VolumeInfo sPrivateUnmountedVol = new VolumeInfo("private2",
+            VolumeInfo.TYPE_PRIVATE, null /*DiskInfo*/, null /*partGuid*/);
+
+    private static final List<VolumeInfo> sVolumes = new ArrayList<>();
+
+    static {
+        sInternalVol.path = sInternalVolPath;
+        sInternalVol.state = STATE_MOUNTED;
+        sInternalVol.fsUuid = sInternalVolUuid;
+
+        sAdoptedVol.path = sAdoptedVolPath;
+        sAdoptedVol.state = STATE_MOUNTED;
+        sAdoptedVol.fsUuid = sAdoptedVolUuid;
+
+        sPublicVol.state = STATE_MOUNTED;
+        sPublicVol.path = sPublicVolPath;
+        sPublicVol.fsUuid = sPublicVolUuid;
+
+        sPrivateUnmountedVol.state = STATE_UNMOUNTED;
+        sPrivateUnmountedVol.path = sPrivateUnmountedVolPath;
+        sPrivateUnmountedVol.fsUuid = sPrivateUnmountedVolUuid;
+
+        sVolumes.add(sInternalVol);
+        sVolumes.add(sAdoptedVol);
+        sVolumes.add(sPublicVol);
+        sVolumes.add(sPrivateUnmountedVol);
+    }
+
+    private static final class MockedApplicationPackageManager extends ApplicationPackageManager {
+        private boolean mForceAllowOnExternal = false;
+        private boolean mAllow3rdPartyOnInternal = true;
+
+        public MockedApplicationPackageManager() {
+            super(null, null);
+        }
+
+        public void setForceAllowOnExternal(boolean forceAllowOnExternal) {
+            mForceAllowOnExternal = forceAllowOnExternal;
+        }
+
+        public void setAllow3rdPartyOnInternal(boolean allow3rdPartyOnInternal) {
+            mAllow3rdPartyOnInternal = allow3rdPartyOnInternal;
+        }
+
+        @Override
+        public boolean isForceAllowOnExternal(Context context) {
+            return mForceAllowOnExternal;
+        }
+
+        @Override
+        public boolean isAllow3rdPartyOnInternal(Context context) {
+            return mAllow3rdPartyOnInternal;
+        }
+    }
+
+    private StorageManager getMockedStorageManager() {
+        StorageManager storageManager = Mockito.mock(StorageManager.class);
+        Mockito.when(storageManager.getVolumes()).thenReturn(sVolumes);
+        Mockito.when(storageManager.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL))
+                .thenReturn(sInternalVol);
+        Mockito.when(storageManager.findVolumeByUuid(sAdoptedVolUuid))
+                .thenReturn(sAdoptedVol);
+        Mockito.when(storageManager.findVolumeByUuid(sPublicVolUuid))
+                .thenReturn(sPublicVol);
+        Mockito.when(storageManager.findVolumeByUuid(sPrivateUnmountedVolUuid))
+                .thenReturn(sPrivateUnmountedVol);
+        return storageManager;
+    }
+
+    private void verifyReturnedVolumes(List<VolumeInfo> actualVols, VolumeInfo... exptectedVols) {
+        boolean failed = false;
+        if (actualVols.size() != exptectedVols.length) {
+            failed = true;
+        } else {
+            for (VolumeInfo vol : exptectedVols) {
+                if (!actualVols.contains(vol)) {
+                    failed = true;
+                    break;
+                }
+            }
+        }
+
+        if (failed) {
+            fail("Wrong volumes returned.\n Expected: " + Arrays.toString(exptectedVols)
+                    + "\n Actual: " + Arrays.toString(actualVols.toArray()));
+        }
+    }
+
+    public void testGetCandidateVolumes_systemApp() throws Exception {
+        ApplicationInfo sysAppInfo = new ApplicationInfo();
+        sysAppInfo.flags = ApplicationInfo.FLAG_SYSTEM;
+
+        StorageManager storageManager = getMockedStorageManager();
+        IPackageManager pm = Mockito.mock(IPackageManager.class);
+
+        MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
+
+        appPkgMgr.setAllow3rdPartyOnInternal(true);
+        appPkgMgr.setForceAllowOnExternal(true);
+        List<VolumeInfo> candidates =
+                appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm);
+        verifyReturnedVolumes(candidates, sInternalVol);
+
+        appPkgMgr.setAllow3rdPartyOnInternal(true);
+        appPkgMgr.setForceAllowOnExternal(false);
+        candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm);
+        verifyReturnedVolumes(candidates, sInternalVol);
+
+        appPkgMgr.setAllow3rdPartyOnInternal(false);
+        appPkgMgr.setForceAllowOnExternal(false);
+        candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm);
+        verifyReturnedVolumes(candidates, sInternalVol);
+
+        appPkgMgr.setAllow3rdPartyOnInternal(false);
+        appPkgMgr.setForceAllowOnExternal(true);
+        candidates = appPkgMgr.getPackageCandidateVolumes(sysAppInfo, storageManager, pm);
+        verifyReturnedVolumes(candidates, sInternalVol);
+    }
+
+    public void testGetCandidateVolumes_3rdParty_internalOnly() throws Exception {
+        ApplicationInfo appInfo = new ApplicationInfo();
+        StorageManager storageManager = getMockedStorageManager();
+
+        IPackageManager pm = Mockito.mock(IPackageManager.class);
+        Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false);
+
+        MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
+
+        // must allow 3rd party on internal, otherwise the app wouldn't have been installed before.
+        appPkgMgr.setAllow3rdPartyOnInternal(true);
+
+        // INSTALL_LOCATION_INTERNAL_ONLY AND INSTALL_LOCATION_UNSPECIFIED are treated the same.
+        int[] locations = {PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY,
+                PackageInfo.INSTALL_LOCATION_UNSPECIFIED};
+
+        for (int location : locations) {
+            appInfo.installLocation = location;
+            appPkgMgr.setForceAllowOnExternal(true);
+            List<VolumeInfo> candidates = appPkgMgr.getPackageCandidateVolumes(
+                    appInfo, storageManager, pm);
+            verifyReturnedVolumes(candidates, sInternalVol, sAdoptedVol);
+
+            appPkgMgr.setForceAllowOnExternal(false);
+            candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm);
+            verifyReturnedVolumes(candidates, sInternalVol);
+        }
+    }
+
+    public void testGetCandidateVolumes_3rdParty_auto() throws Exception {
+        ApplicationInfo appInfo = new ApplicationInfo();
+        StorageManager storageManager = getMockedStorageManager();
+
+        IPackageManager pm = Mockito.mock(IPackageManager.class);
+
+        MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
+        appPkgMgr.setForceAllowOnExternal(true);
+
+        // INSTALL_LOCATION_AUTO AND INSTALL_LOCATION_PREFER_EXTERNAL are treated the same.
+        int[] locations = {PackageInfo.INSTALL_LOCATION_AUTO,
+                PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL};
+
+        for (int location : locations) {
+            appInfo.installLocation = location;
+            appInfo.flags = 0;
+
+            appInfo.volumeUuid = sInternalVolUuid;
+            Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false);
+            appPkgMgr.setAllow3rdPartyOnInternal(true);
+            List<VolumeInfo> candidates = appPkgMgr.getPackageCandidateVolumes(
+                    appInfo, storageManager, pm);
+            verifyReturnedVolumes(candidates, sInternalVol, sAdoptedVol);
+
+            appInfo.volumeUuid = sInternalVolUuid;
+            appPkgMgr.setAllow3rdPartyOnInternal(true);
+            Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(true);
+            candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm);
+            verifyReturnedVolumes(candidates, sInternalVol);
+
+            appInfo.flags = ApplicationInfo.FLAG_EXTERNAL_STORAGE;
+            appInfo.volumeUuid = sAdoptedVolUuid;
+            appPkgMgr.setAllow3rdPartyOnInternal(false);
+            candidates = appPkgMgr.getPackageCandidateVolumes(appInfo, storageManager, pm);
+            verifyReturnedVolumes(candidates, sAdoptedVol);
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 2a3c22c..ca4141a 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -215,4 +215,46 @@
         // DEV: Released API 20
         verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
     }
+
+    /**
+     * Unit test for PackageParser.getActivityConfigChanges().
+     * If the bit is 1 in the original configChanges, it is still 1 in the final configChanges.
+     * If the bit is 0 in the original configChanges and the bit is not set to 1 in
+     * restartOnConfigChanges, the bit is changed to 1 in the final configChanges by default.
+     */
+    @Test
+    public void testGetActivityConfigChanges() {
+        // Not set in either configChanges or restartOnConfigChanges.
+        int configChanges = 0x0000; // 00000000.
+        int restartOnConfigChanges = 0x0000; // 00000000.
+        int finalConfigChanges =
+                PackageParser.getActivityConfigChanges(configChanges, restartOnConfigChanges);
+        assertEquals(0x0003, finalConfigChanges); // Should be 00000011.
+
+        // Not set in configChanges, but set in restartOnConfigChanges.
+        configChanges = 0x0000; // 00000000.
+        restartOnConfigChanges = 0x0003; // 00000011.
+        finalConfigChanges =
+                PackageParser.getActivityConfigChanges(configChanges, restartOnConfigChanges);
+        assertEquals(0x0000, finalConfigChanges); // Should be 00000000.
+
+        // Set in configChanges.
+        configChanges = 0x0003; // 00000011.
+        restartOnConfigChanges = 0X0000; // 00000000.
+        finalConfigChanges =
+                PackageParser.getActivityConfigChanges(configChanges, restartOnConfigChanges);
+        assertEquals(0x0003, finalConfigChanges); // Should be 00000011.
+
+        restartOnConfigChanges = 0x0003; // 00000011.
+        finalConfigChanges =
+                PackageParser.getActivityConfigChanges(configChanges, restartOnConfigChanges);
+        assertEquals(0x0003, finalConfigChanges); // Should still be 00000011.
+
+        // Other bit set in configChanges.
+        configChanges = 0x0080; // 10000000, orientation.
+        restartOnConfigChanges = 0x0000; // 00000000.
+        finalConfigChanges =
+                PackageParser.getActivityConfigChanges(configChanges, restartOnConfigChanges);
+        assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
+    }
 }
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index 29020ba..5bfff26 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -169,25 +169,6 @@
         assertNull(activeScorer);
     }
 
-    public void testIsCallerActiveScorer_providerNotAvailable() throws Exception {
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
-        assertFalse(mNetworkScorerAppManager.isCallerActiveScorer(924));
-    }
-
-    public void testIsCallerActiveScorer_providerAvailable() throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-        mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
-
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
-        assertTrue(mNetworkScorerAppManager.isCallerActiveScorer(924));
-        assertFalse(mNetworkScorerAppManager.isCallerActiveScorer(925));
-    }
-
     private void setNetworkRecommendationPackageNames(String... names) {
         if (names == null) {
             names = new String[0];
diff --git a/core/tests/coretests/src/android/net/RecommendationRequestTest.java b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
index 31560b0..bd25500 100644
--- a/core/tests/coretests/src/android/net/RecommendationRequestTest.java
+++ b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
@@ -3,12 +3,16 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.os.Parcel;
+import android.os.SystemClock;
 import android.test.AndroidTestCase;
 
 public class RecommendationRequestTest extends AndroidTestCase {
     private ScanResult[] mScanResults;
-    private WifiConfiguration mConfiguration;
-    private NetworkCapabilities mCapabilities;
+    private WifiConfiguration mDefaultConfig;
+    private WifiConfiguration mConnectedConfig;
+    private WifiConfiguration[] mConnectableConfigs;
+    private int mLastSelectedNetworkId;
+    private long mLastSelectedNetworkTimestamp;
 
     @Override
     public void setUp() throws Exception {
@@ -29,45 +33,73 @@
                 8 /*centerFreq0*/,
                 9 /*centerFreq1*/,
                 false /*is80211McRTTResponder*/);
-        mConfiguration = new WifiConfiguration();
-        mConfiguration.SSID = "RecommendationRequestTest";
-        mCapabilities = new NetworkCapabilities()
-                .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
+        mDefaultConfig = new WifiConfiguration();
+        mDefaultConfig.SSID = "default_config";
+        mConnectedConfig = new WifiConfiguration();
+        mConnectedConfig.SSID = "connected_config";
+        mConnectableConfigs = new WifiConfiguration[] {mDefaultConfig, mConnectedConfig};
+        mLastSelectedNetworkId = 5;
+        mLastSelectedNetworkTimestamp = SystemClock.elapsedRealtime();
     }
 
     public void testParceling() throws Exception {
         RecommendationRequest request = new RecommendationRequest.Builder()
-                .setCurrentRecommendedWifiConfig(mConfiguration)
+                .setDefaultWifiConfig(mDefaultConfig)
                 .setScanResults(mScanResults)
-                .setNetworkCapabilities(mCapabilities)
+                .setConnectedWifiConfig(mConnectedConfig)
+                .setConnectableConfigs(mConnectableConfigs)
+                .setLastSelectedNetwork(mLastSelectedNetworkId, mLastSelectedNetworkTimestamp)
                 .build();
 
         RecommendationRequest parceled = passThroughParcel(request);
-        assertEquals(request.getCurrentSelectedConfig().SSID,
-                parceled.getCurrentSelectedConfig().SSID);
-        assertEquals(request.getRequiredCapabilities(), parceled.getRequiredCapabilities());
+        assertEquals(request.getDefaultWifiConfig().SSID,
+                parceled.getDefaultWifiConfig().SSID);
+        assertEquals(request.getConnectedConfig().SSID,
+                parceled.getConnectedConfig().SSID);
         ScanResult[] parceledScanResults = parceled.getScanResults();
         assertNotNull(parceledScanResults);
         assertEquals(mScanResults.length, parceledScanResults.length);
         for (int i = 0; i < mScanResults.length; i++) {
             assertEquals(mScanResults[i].SSID, parceledScanResults[i].SSID);
         }
+        WifiConfiguration[] parceledConfigs = parceled.getConnectableConfigs();
+        for (int i = 0; i < parceledConfigs.length; i++) {
+            assertEquals(mConnectableConfigs[i].SSID, parceledConfigs[i].SSID);
+        }
+        assertEquals(mLastSelectedNetworkId, parceled.getLastSelectedNetworkId());
+        assertEquals(mLastSelectedNetworkTimestamp, parceled.getLastSelectedNetworkTimestamp());
     }
 
     public void testParceling_nullScanResults() throws Exception {
         RecommendationRequest request = new RecommendationRequest.Builder()
-                .setCurrentRecommendedWifiConfig(mConfiguration)
-                .setNetworkCapabilities(mCapabilities)
+                .setDefaultWifiConfig(mDefaultConfig)
                 .build();
 
         RecommendationRequest parceled = passThroughParcel(request);
-        assertEquals(request.getCurrentSelectedConfig().SSID,
-                parceled.getCurrentSelectedConfig().SSID);
-        assertEquals(request.getRequiredCapabilities(), parceled.getRequiredCapabilities());
         ScanResult[] parceledScanResults = parceled.getScanResults();
         assertNull(parceledScanResults);
     }
 
+    public void testParceling_nullWifiConfigArray() throws Exception {
+        RecommendationRequest request = new RecommendationRequest.Builder()
+                .setDefaultWifiConfig(mDefaultConfig)
+                .build();
+
+        RecommendationRequest parceled = passThroughParcel(request);
+        WifiConfiguration[] parceledConfigs = parceled.getConnectableConfigs();
+        assertNull(parceledConfigs);
+    }
+
+    public void testParceling_unsetLastSelectedNetwork() throws Exception {
+        RecommendationRequest request = new RecommendationRequest.Builder()
+                .build();
+
+        RecommendationRequest parceled = passThroughParcel(request);
+
+        assertEquals(0, parceled.getLastSelectedNetworkId());
+        assertEquals(0, parceled.getLastSelectedNetworkTimestamp());
+    }
+
     private RecommendationRequest passThroughParcel(RecommendationRequest request) {
         Parcel p = Parcel.obtain();
         RecommendationRequest output = null;
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index 37f0007..ff98eb7 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -18,15 +18,20 @@
 
 import android.content.Context;
 import android.os.Environment;
+import android.os.ProxyFileDescriptorCallback;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
 import com.android.frameworks.coretests.R;
-
+import com.android.internal.os.FuseAppLoop;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.util.concurrent.ThreadFactory;
 import java.io.File;
 import java.io.FileInputStream;
 
@@ -243,4 +248,47 @@
         verifyObb1Contents(filePath);
         unmountObb(filePath, DONT_FORCE);
     }
+
+    @LargeTest
+    public void testOpenProxyFileDescriptor() throws Exception {
+        final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() {
+            @Override
+            public long onGetSize() throws ErrnoException {
+                return 0;
+            }
+
+            @Override
+            public void onRelease() {}
+        };
+
+        final MyThreadFactory factory = new MyThreadFactory();
+        int firstMountId;
+        try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
+                ParcelFileDescriptor.MODE_READ_ONLY, callback, factory)) {
+            assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
+            firstMountId = mSm.getProxyFileDescriptorMountPointId();
+            assertNotSame(-1, firstMountId);
+        }
+
+        // After closing descriptor, the loop should terminate.
+        factory.thread.join(3000);
+        assertEquals(Thread.State.TERMINATED, factory.thread.getState());
+
+        // StorageManager should mount another bridge on the next open request.
+        try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
+                ParcelFileDescriptor.MODE_WRITE_ONLY, callback, factory)) {
+            assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
+            assertNotSame(firstMountId, mSm.getProxyFileDescriptorMountPointId());
+        }
+    }
+
+    private static class MyThreadFactory implements ThreadFactory {
+        Thread thread = null;
+
+        @Override
+        public Thread newThread(Runnable r) {
+            thread = new Thread(r);
+            return thread;
+        }
+    }
 }
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index b0ce2c8..3fbf169 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -364,4 +364,20 @@
         // one or more activity can handle this intent.
         assertTrue(resolveInfoList.size() > 0);
     }
+
+    @SmallTest
+    public void testValidSsaid() {
+        ContentResolver r = getContext().getContentResolver();
+
+        // Verify ssaid
+        String ssaid = Settings.Secure.getString(r, Settings.Secure.ANDROID_ID);
+        assertTrue(ssaid != null);
+        assertTrue(ssaid.length() == 16);
+
+        String ssaid2 = Settings.Secure.getString(r, Settings.Secure.ANDROID_ID);
+        assertTrue(ssaid2 != null);
+        assertTrue(ssaid2.length() == 16);
+
+        assertTrue(ssaid.equals(ssaid2));
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index aab4698..daebf88 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -222,7 +222,7 @@
     private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
         List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
         for (int i = 0; i < numberOfResults; i++) {
-            infoList.add(ChooserDataProvider.createResolvedComponentInfo(i));
+            infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
         }
         return infoList;
     }
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 41016e1..c446f3c 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -24,11 +24,10 @@
 
 import static org.mockito.Mockito.mock;
 
-
-/**
- * Simple wrapper around chooser activity to be able to initiate it under test
- */
 public class ChooserWrapperActivity extends ChooserActivity {
+    /*
+     * Simple wrapper around chooser activity to be able to initiate it under test
+     */
     static final OverrideData sOverrides = new OverrideData();
     private UsageStatsManager mUsm;
 
@@ -94,4 +93,4 @@
             resolverListController = mock(ResolverListController.class);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
new file mode 100644
index 0000000..84b844a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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.app;
+
+import com.android.internal.R;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static android.os.SystemClock.sleep;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Resolver activity instrumentation tests
+ */
+@RunWith(AndroidJUnit4.class)
+public class ResolverActivityTest {
+    @Rule
+    public ActivityTestRule<ResolverWrapperActivity> mActivityRule =
+            new ActivityTestRule<>(ResolverWrapperActivity.class, false,
+                    false);
+
+    @Before
+    public void cleanOverrideData() {
+        sOverrides.reset();
+    }
+
+    @Test
+    public void twoOptionsAndUserSelectsOne() throws InterruptedException {
+        Intent sendIntent = createSendImageIntent();
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+        waitForIdle();
+
+        assertThat(activity.getAdapter().getCount(), is(2));
+
+        ResolveInfo[] chosen = new ResolveInfo[1];
+        sOverrides.onSafelyStartCallback = targetInfo -> {
+            chosen[0] = targetInfo.getResolveInfo();
+            return true;
+        };
+
+        ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
+        onView(withText(toChoose.activityInfo.name))
+                .perform(click());
+        onView(withId(R.id.button_once))
+                .perform(click());
+        waitForIdle();
+        assertThat(chosen[0], is(toChoose));
+    }
+
+    @Test
+    public void hasLastChosenActivity() throws Exception {
+        Intent sendIntent = createSendImageIntent();
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+        when(sOverrides.resolverListController.getLastChosen())
+                .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0));
+
+        final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent);
+        waitForIdle();
+
+        // The other entry is filtered to the last used slot
+        assertThat(activity.getAdapter().getCount(), is(1));
+
+        ResolveInfo[] chosen = new ResolveInfo[1];
+        sOverrides.onSafelyStartCallback = targetInfo -> {
+            chosen[0] = targetInfo.getResolveInfo();
+            return true;
+        };
+
+        ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0);
+        onView(withId(R.id.title)).perform(click());
+        onView(withId(R.id.button_once))
+                .perform(click());
+        waitForIdle();
+        assertThat(chosen[0], is(toChoose));
+    }
+
+    private Intent createSendImageIntent() {
+        Intent sendIntent = new Intent();
+        sendIntent.setAction(Intent.ACTION_SEND);
+        sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
+        sendIntent.setType("image/jpeg");
+        return sendIntent;
+    }
+
+    private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
+        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+        for (int i = 0; i < numberOfResults; i++) {
+            infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+        }
+        return infoList;
+    }
+
+    private void waitForIdle() {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserDataProvider.java b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
similarity index 94%
rename from core/tests/coretests/src/com/android/internal/app/ChooserDataProvider.java
rename to core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
index f6f63f1..ae06306 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserDataProvider.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverDataProvider.java
@@ -22,16 +22,15 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.os.UserHandle;
-import android.service.chooser.ChooserTarget;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * Utility class used by chooser tests to create mock data
+ * Utility class used by resolver tests to create mock data
  */
-class ChooserDataProvider {
+class ResolverDataProvider {
 
     static ResolverActivity.ResolvedComponentInfo createResolvedComponentInfo(int i) {
         return new ResolverActivity.ResolvedComponentInfo(createComponentName(i),
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
new file mode 100644
index 0000000..163211e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -0,0 +1,91 @@
+/*
+ * 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.app;
+
+import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+
+import java.util.function.Function;
+
+import static org.mockito.Mockito.mock;
+
+
+/*
+ * Simple wrapper around chooser activity to be able to initiate it under test
+ */
+public class ResolverWrapperActivity extends ResolverActivity {
+    static final OverrideData sOverrides = new OverrideData();
+    private UsageStatsManager mUsm;
+
+    ResolveListAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    @Override
+    public boolean isVoiceInteraction() {
+        if (sOverrides.isVoiceInteraction != null) {
+            return sOverrides.isVoiceInteraction;
+        }
+        return super.isVoiceInteraction();
+    }
+
+    @Override
+    public void safelyStartActivity(TargetInfo cti) {
+        if (sOverrides.onSafelyStartCallback != null &&
+                sOverrides.onSafelyStartCallback.apply(cti)) {
+            return;
+        }
+        super.safelyStartActivity(cti);
+    }
+
+    @Override
+    protected ResolverListController createListController() {
+        return sOverrides.resolverListController;
+    }
+
+    @Override
+    public PackageManager getPackageManager() {
+        if (sOverrides.createPackageManager != null) {
+            return sOverrides.createPackageManager.apply(super.getPackageManager());
+        }
+        return super.getPackageManager();
+    }
+
+    /**
+     * We cannot directly mock the activity created since instrumentation creates it.
+     * <p>
+     * Instead, we use static instances of this object to modify behavior.
+     */
+    static class OverrideData {
+        @SuppressWarnings("Since15")
+        public Function<PackageManager, PackageManager> createPackageManager;
+        public Function<TargetInfo, Boolean> onSafelyStartCallback;
+        public ResolverListController resolverListController;
+        public Boolean isVoiceInteraction;
+
+        public void reset() {
+            onSafelyStartCallback = null;
+            isVoiceInteraction = null;
+            createPackageManager = null;
+            resolverListController = mock(ResolverListController.class);
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
index e3f754c..1c19d88 100644
--- a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
+++ b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
@@ -1,5 +1,21 @@
+/*
+ * 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.logging;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import junit.framework.TestCase;
 
 public class LogBuilderTest extends TestCase {
@@ -15,6 +31,57 @@
         assertEquals("two", out[3]);
     }
 
+    public void testSerializeDeserialize() {
+        int category = 10;
+        int type = 11;
+        int subtype = 12;
+        long timestamp = 1484669007890L;
+        String packageName = "com.foo.bar";
+        String counterName = "sheep";
+        int bucket = 13;
+        int value = 14;
+
+        LogBuilder builder = new LogBuilder(category);
+        builder.setType(type);
+        builder.setSubtype(subtype);
+        builder.setTimestamp(timestamp);
+        builder.setPackageName(packageName);
+        builder.setCounterName(counterName);
+        builder.setCounterBucket(bucket);
+        builder.setCounterValue(value);
+        builder.addTaggedData(1, "one");
+        builder.addTaggedData(2, "two");
+
+        Object[] out = builder.serialize();
+        LogBuilder parsed = new LogBuilder(out);
+
+        assertEquals(category, parsed.getCategory());
+        assertEquals(type, parsed.getType());
+        assertEquals(subtype, parsed.getSubtype());
+        assertEquals(timestamp, parsed.getTimestamp());
+        assertEquals(packageName, parsed.getPackageName());
+        assertEquals(counterName, parsed.getCounterName());
+        assertEquals(bucket, parsed.getCounterBucket());
+        assertEquals(value, parsed.getCounterValue());
+        assertEquals("one", parsed.getTaggedData(1));
+        assertEquals("two", parsed.getTaggedData(2));
+    }
+
+    public void testIntBucket() {
+        LogBuilder builder = new LogBuilder(0);
+        builder.setCounterBucket(100);
+        assertEquals(100, builder.getCounterBucket());
+        assertEquals(false, builder.isLongCounterBucket());
+    }
+
+    public void testLongBucket() {
+        long longBucket = Long.MAX_VALUE;
+        LogBuilder builder = new LogBuilder(0);
+        builder.setCounterBucket(longBucket);
+        assertEquals(longBucket, builder.getCounterBucket());
+        assertEquals(true, builder.isLongCounterBucket());
+    }
+
     public void testInvalidInputThrows() {
         LogBuilder builder = new LogBuilder(0);
         boolean threw = false;
@@ -24,7 +91,7 @@
             threw = true;
         }
         assertTrue(threw);
-        assertEquals(0, builder.serialize().length);
+        assertEquals(2, builder.serialize().length);
     }
 
     public void testValidInputTypes() {
@@ -40,4 +107,21 @@
         assertEquals(123.0F, out[7]);
     }
 
+    public void testCategoryDefault() {
+        LogBuilder builder = new LogBuilder(10);
+        Object[] out = builder.serialize();
+        assertEquals(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY, out[0]);
+        assertEquals(10, out[1]);
+    }
+
+    public void testGiantLogOmitted() {
+        LogBuilder badBuilder = new LogBuilder(0);
+        StringBuilder b = new StringBuilder();
+        for (int i = 0; i < 4000; i++) {
+            b.append("test, " + i);
+        }
+        badBuilder.addTaggedData(100, b.toString());
+        assertTrue(badBuilder.serialize().length < LogBuilder.MAX_SERIALIZED_SIZE);
+    }
+
 }
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java
new file mode 100644
index 0000000..5a7766b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+public class CounterParserTest extends ParserTest {
+
+    public CounterParserTest() {
+        mParser = new CounterParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[2];
+        objects[0] = name;
+        objects[1] = value;
+
+        validateGoodData(name, value, objects);
+    }
+
+    private void validateGoodData(String name, int value, Object[] objects) {
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, times(1)).incrementBy(mNameCaptor.capture(), mCountCaptor.capture());
+
+        assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
+        assertEquals(value, mCountCaptor.getValue().intValue());
+    }
+
+    public void testMissingName() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testWrongTypes() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[2];
+        objects[0] = value;
+        objects[1] = name;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[3];
+        objects[0] = name;
+        objects[1] = value;
+        objects[2] = "foo";
+
+        validateGoodData(name, value, objects);
+    }
+
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java
new file mode 100644
index 0000000..1bd9d83
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+public class HistogramParserTest extends ParserTest {
+
+    public HistogramParserTest() {
+        mParser = new HistogramParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        String name = "foo";
+        int bucket = 5;
+        Object[] objects = new Object[2];
+        objects[0] = name;
+        objects[1] = bucket;
+
+        validateGoodData(name, bucket, objects);
+    }
+
+    private void validateGoodData(String name, int bucket, Object[] objects) {
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, times(1))
+                .incrementIntHistogram(mNameCaptor.capture(), mCountCaptor.capture());
+
+        assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
+        assertEquals(bucket, mCountCaptor.getValue().intValue());
+    }
+
+    public void testMissingName() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testWrongTypes() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[2];
+        objects[0] = value;
+        objects[1] = name;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        String name = "foo";
+        int bucket = 5;
+        Object[] objects = new Object[3];
+        objects[0] = name;
+        objects[1] = bucket;
+        objects[2] = "foo";
+
+        validateGoodData(name, bucket, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java
new file mode 100644
index 0000000..0bff850
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class LockscreenGestureParserTest extends ParserTest {
+
+    public LockscreenGestureParserTest() {
+        mParser = new LockscreenGestureParser();
+    }
+
+    public void testSwipeUpUnlock() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_UNLOCK, 1, 359, 6382);
+    }
+
+    public void testSwipeToShade() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_SHADE, 2, 324, 0);
+    }
+
+    public void testTapLockHint() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_HINT, 3, 0, 0);
+    }
+
+    public void testCamera() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_CAMERA, 4, 223, 1756);
+    }
+
+    public void testDialer() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_DIALER, 5, 163, 861);
+    }
+
+    public void testTapToLock() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_LOCK, 6, 0, 0);
+    }
+
+    public void testTapOnNotification() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_NOTE, 7, 0, 0);
+    }
+
+    public void testLockscreenQuickSettings() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_QS, 8, 284, 3824);
+    }
+
+    public void testShadePullQuickSettings() throws Throwable {
+        validate(MetricsEvent.ACTION_SHADE_QS_PULL, 9, 175, 3444);
+    }
+
+    public void testShadeTapQuickSettings() throws Throwable {
+        validate(MetricsEvent.ACTION_SHADE_QS_TAP, 10, 0, 0);
+    }
+
+    private void validate(int view, int type, int len, int vel) {
+        int t = 1000;
+        Object[] objects = new Object[3];
+        objects[0] = type;
+        objects[1] = len;
+        objects[2] = vel;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[4];
+        objects[0] = 1;
+        objects[1] = 0;
+        objects[2] = 0;
+        objects[3] = "foo";
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java
new file mode 100644
index 0000000..2119c25
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationActionClickedParserTest extends ParserTest {
+
+    public NotificationActionClickedParserTest() {
+        mParser = new NotificationActionClickedParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[2];
+        objects[0] = mKey;
+        objects[1] = index;
+
+        validateGoodData(t, "", index, objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[2];
+        objects[0] = mTaggedKey;
+        objects[1] = index;
+
+        validateGoodData(t, mTag, index, objects);
+    }
+
+    private LogBuilder validateGoodData(int t, String tag, int index, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM_ACTION, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+        assertEquals(index, proto.getSubtype());
+        return proto;
+    }
+
+    public void testMissingData() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = 2;
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "foo";
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMncTimestamps() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[5];
+        objects[0] = mKey;
+        objects[1] = index;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceUpdateMillis;
+        objects[4] = mSinceVisibleMillis;
+
+        LogBuilder proto = validateGoodData(t, "", index, objects);
+        validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
+                mSinceVisibleMillis);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[6];
+        objects[0] = mKey;
+        objects[1] = index;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceUpdateMillis;
+        objects[4] = mSinceVisibleMillis;
+        objects[5] = "foo";
+
+        validateGoodData(t, "", index, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java
new file mode 100644
index 0000000..1e117ee
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.mockito.ArgumentCaptor;
+
+public class NotificationAlertParserTest extends ParserTest {
+    protected ArgumentCaptor<Boolean> mConfigCaptor;
+
+    private final int mTime = 1000;
+
+    public NotificationAlertParserTest() {
+        mParser = new NotificationAlertParser();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mConfigCaptor = ArgumentCaptor.forClass(Boolean.class);
+        when(mLogger.getConfig(anyString())).thenReturn(false);
+    }
+
+    public void testBuzzOnly() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = 0;
+        objects[3] = 0;
+
+        validateInteraction(true, false, false, objects);
+    }
+
+    public void testBeepOnly() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 1;
+        objects[3] = 0;
+
+        validateInteraction(false, true, false, objects);
+    }
+
+    public void testBlinkOnly() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 0;
+        objects[3] = 1;
+
+        validateInteraction(false, false, true, objects);
+    }
+
+    public void testBuzzBlink() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = 0;
+        objects[3] = 1;
+
+        validateInteraction(true, false, true, objects);
+    }
+
+    public void testBeepBlink() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 1;
+        objects[3] = 1;
+
+        validateInteraction(false, true, true, objects);
+    }
+
+    public void testIgnoreExtraArgs() throws Throwable {
+        Object[] objects = new Object[5];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 1;
+        objects[3] = 1;
+        objects[4] = "foo";
+
+        validateInteraction(false, true, true, objects);
+    }
+
+    private void validateInteraction(boolean buzz, boolean beep, boolean blink, Object[] objects) {
+        int flags = 0;
+        int counts = 0;
+        if (buzz) {
+            counts++;
+            flags |= NotificationAlertParser.BUZZ;
+        }
+        if (beep) {
+            counts++;
+            flags |= NotificationAlertParser.BEEP;
+        }
+        if (blink) {
+            counts++;
+            flags |= NotificationAlertParser.BLINK;
+        }
+
+        mParser.parseEvent(mLogger, mTime, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(mTime, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ALERT, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, mTag);
+        assertEquals(flags, proto.getSubtype());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java
new file mode 100644
index 0000000..de16919
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.List;
+
+public class NotificationCanceledParserTest extends ParserTest {
+
+    public NotificationCanceledParserTest() {
+        mParser = new NotificationCanceledParser();
+    }
+
+    public void testGoodProto() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[2];
+        objects[0] = mKey;
+        objects[1] = reason;
+
+        validateGoodData(t, "", reason, objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[2];
+        objects[0] = mTaggedKey;
+        objects[1] = reason;
+
+        validateGoodData(t, mTag, reason, objects);
+    }
+
+    private void validateGoodData(int t, String tag, int reason, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_DISMISS, proto.getType());
+        assertEquals(reason, proto.getSubtype());
+    }
+
+    public void testLifetime() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = mSinceCreationMillis;
+
+        validateTimers(t, objects, mSinceCreationMillis, 0, 0);
+    }
+
+    public void testExposure() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[4];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceVisibleMillis;
+
+
+        validateTimers(t, objects, mSinceCreationMillis, 0, mSinceVisibleMillis);
+    }
+
+    public void testFreshness() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[5];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceUpdateMillis;
+        objects[4] = mSinceVisibleMillis;
+
+        validateTimers(t, objects, mSinceCreationMillis, mSinceUpdateMillis, mSinceVisibleMillis);
+    }
+
+    private void validateTimers(int t, Object[] objects, int life, int freshness, int exposure) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        validateNotificationTimes(proto, life, freshness, exposure);
+    }
+
+    public void verifyReason(int reason, boolean intentional, boolean important, String counter)
+            throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = mKey;
+        objects[1] = reason;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        if (intentional) {
+            verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
+        }
+    }
+
+    public void testDelegateCancel() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL,
+                true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
+    }
+
+    public void testDelegateCancelAll() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL_ALL,
+                true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
+    }
+
+    public void testListenerCancel() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL,
+                false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
+    }
+
+    public void testListenerCancelAll() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL_ALL,
+                false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
+    }
+
+    public void testDelegateClick() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_DELEGATE_CLICK,
+                true, true, TronCounters.TRON_NOTE_DISMISS_BY_CLICK);
+    }
+
+    public void testBanned() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_PACKAGE_BANNED,
+                false, true, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
+    }
+
+    public void testUnknownReason() throws Throwable {
+        verifyReason(1001010, false, false, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
+    }
+
+    public void testMissingData() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = 2;
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "foo";
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = "foo";
+
+        validateGoodData(t, "", reason, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java
new file mode 100644
index 0000000..2f61dd7
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationClickedParserTest extends ParserTest {
+
+    public NotificationClickedParserTest() {
+        mParser = new NotificationClickedParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[1];
+        objects[0] = mKey;
+
+        validateGoodData(t, "", objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[1];
+        objects[0] = mTaggedKey;
+
+        validateGoodData(t, mTag, objects);
+    }
+
+    private LogBuilder validateGoodData(int t, String tag, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+        assertEquals(0, proto.getSubtype());
+        return proto;
+    }
+
+    public void testMissingKey() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "foo";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMncTimestamps() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[4];
+        objects[0] = mKey;
+        objects[1] = mSinceCreationMillis;
+        objects[2] = mSinceUpdateMillis;
+        objects[3] = mSinceVisibleMillis;
+
+        LogBuilder proto = validateGoodData(t, "", objects);
+        validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
+                mSinceVisibleMillis);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[5];
+        objects[0] = mKey;
+        objects[1] = mSinceCreationMillis;
+        objects[2] = mSinceUpdateMillis;
+        objects[3] = mSinceVisibleMillis;
+        objects[4] = "foo";
+
+        validateGoodData(t, "", objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java
new file mode 100644
index 0000000..86b4a45
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationExpansionParserTest extends ParserTest {
+
+    public NotificationExpansionParserTest() {
+        mParser = new NotificationExpansionParser();
+    }
+
+    public void testExpandedByUser() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        validateGoodData(t, "", objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[3];
+        objects[0] = mTaggedKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        validateGoodData(t, mTag, objects);
+    }
+
+    private LogBuilder validateGoodData(int t, String tag, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_DETAIL, proto.getType());
+        return proto;
+    }
+
+    public void testAutoExpand() throws Throwable {
+        int t = 1000;
+        int byUser = 0;
+        int expanded = 1;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testCollapsedByUser() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 0;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testAutoCollapsed() throws Throwable {
+        int t = 1000;
+        int byUser = 0;
+        int expanded = 0;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMissingData() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[3];
+        objects[0] = 2;
+        objects[1] = 5;
+        objects[2] = 7;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[3];
+        objects[0] = "foo";
+        objects[1] = 5;
+        objects[2] = 2;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMncTimestamps() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[6];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+        objects[3] = mSinceCreationMillis;
+        objects[4] = mSinceUpdateMillis;
+        objects[5] = mSinceVisibleMillis;
+
+        LogBuilder proto = validateGoodData(t, "", objects);
+        validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
+                mSinceVisibleMillis);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[7];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+        objects[3] = mSinceCreationMillis;
+        objects[4] = mSinceUpdateMillis;
+        objects[5] = mSinceVisibleMillis;
+        objects[6] = "foo";
+
+        validateGoodData(t, "", objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java
new file mode 100644
index 0000000..b509700
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java
@@ -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.
+ */
+package com.android.internal.logging.legacy;
+
+import android.test.InstrumentationTestCase;
+
+public class NotificationKeyTest extends InstrumentationTestCase {
+
+    private final NotificationKey mKey;
+
+    public NotificationKeyTest() {
+        mKey = new NotificationKey();
+    }
+
+    public void testGoodKey() throws Throwable {
+        assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|null|10090"));
+
+        assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
+        assertEquals("", mKey.mTag);
+        assertEquals(31338, mKey.mId);
+        assertEquals(1, mKey.mUser);
+        assertEquals(10090, mKey.mUid);
+    }
+
+    public void testTaggedKey() throws Throwable {
+        assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|foo|10090"));
+
+        assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
+        assertEquals("foo", mKey.mTag);
+        assertEquals(31338, mKey.mId);
+        assertEquals(1, mKey.mUser);
+        assertEquals(10090, mKey.mUid);
+    }
+
+    public void testEmptyTag() throws Throwable {
+        assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338||10090"));
+
+        assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
+        assertEquals("", mKey.mTag);
+        assertEquals(31338, mKey.mId);
+        assertEquals(1, mKey.mUser);
+        assertEquals(10090, mKey.mUid);
+    }
+
+    public void testBadKeys() throws Throwable {
+        assertFalse(mKey.parse(null));
+        assertFalse(mKey.parse(""));
+        assertFalse(mKey.parse("foo"));  // not a key
+        assertFalse(mKey.parse("1|com.android.example.notificationshowcase|31338|null"));
+        assertFalse(mKey.parse("bar|com.android.example.notificationshowcase|31338|null|10090"));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java
new file mode 100644
index 0000000..3efc48f
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationPanelHiddenParserTest extends ParserTest {
+
+    public NotificationPanelHiddenParserTest() {
+        mParser = new NotificationPanelHiddenParser();
+    }
+
+    public void testNoInput() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[0];
+
+        validateGoodData(t, objects);
+
+    }
+
+    public void testIgnoreExtraneousInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "nothing to see here";
+
+        validateGoodData(0, objects);
+    }
+
+    private void validateGoodData(int t, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java
new file mode 100644
index 0000000..34dda98
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationPanelRevealedParserTest extends ParserTest {
+
+    public NotificationPanelRevealedParserTest() {
+        mParser = new NotificationPanelRevealedParser();
+    }
+
+    public void testLollipopInput() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+    }
+
+    public void testMncData() throws Throwable {
+        int t = 1000;
+        int n = 5;
+        Object[] objects = new Object[1];
+        objects[0] = Integer.valueOf(n);
+
+        validateMncData(t, n, objects);
+    }
+
+    private void validateMncData(int t, int n, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+    }
+
+    public void testBadInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "This is not the integer you're looking for.";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int n = 5;
+        Object[] objects = new Object[2];
+        objects[0] = Integer.valueOf(n);
+        objects[1] = "foo";
+
+        validateMncData(t, n, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java
new file mode 100644
index 0000000..cc5421c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.logging.legacy;
+
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.mockito.ArgumentCaptor;
+
+public class NotificationVisibilityParserTest extends ParserTest {
+    private final int mCreationTime = 23124;
+    private final int mUpdateTime = 3412;
+    private final int mTime = 1000;
+
+    public NotificationVisibilityParserTest() {
+        mParser = new NotificationVisibilityParser();
+    }
+
+    public void testReveal() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+
+        validateInteraction(true, mUpdateTime, 0, objects);
+    }
+
+    public void testHide() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+
+        validateInteraction(false, mUpdateTime, 0, objects);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        Object[] objects = new Object[5];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+        objects[4] = "foo";
+
+        validateInteraction(true, mUpdateTime, 0, objects);
+    }
+
+    public void testMarshmallowIndexData() throws Throwable {
+        Object[] objects = new Object[6];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+        objects[4] = 0;
+        objects[5] = 3;
+
+        validateInteraction(true, mUpdateTime, 3, objects);
+    }
+
+    private void validateInteraction(boolean visible, int freshness, int index, Object[] objects)    {
+        mParser.parseEvent(mLogger, mTime, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(mTime, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, mTag);
+        validateNotificationTimes(proto, mCreationTime, mUpdateTime);
+        assertEquals(index, proto.getTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX));
+        assertEquals(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE, proto.getType());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/ParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/ParserTest.java
new file mode 100644
index 0000000..2e5c6d2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/ParserTest.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.internal.logging.legacy;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.when;
+
+import junit.framework.TestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.OngoingStubbing;
+
+/**
+ * Common functions and temporaries for parser tests.
+ */
+public class ParserTest extends TestCase {
+    @Mock
+    protected TronLogger mLogger;
+
+    protected TagParser mParser;
+
+    protected LogBuilder[] mProto;
+    protected ArgumentCaptor<LogBuilder> mProtoCaptor;
+    protected ArgumentCaptor<String> mNameCaptor;
+    protected ArgumentCaptor<Integer> mCountCaptor;
+    protected String mKey = "0|com.android.example.notificationshowcase|31338|null|10090";
+    protected String mTaggedKey = "0|com.android.example.notificationshowcase|31338|badger|10090";
+    protected String mKeyPackage = "com.android.example.notificationshowcase";
+    protected String mTag = "badger";
+    protected int mId = 31338;
+    protected int mSinceCreationMillis = 5000;
+    protected int mSinceUpdateMillis = 1012;
+    protected int mSinceVisibleMillis = 323;
+
+
+    public ParserTest() {
+        mProto = new LogBuilder[5];
+        for (int i = 0; i < mProto.length; i++) {
+            mProto[i] = new LogBuilder(MetricsEvent.VIEW_UNKNOWN);
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        MockitoAnnotations.initMocks(this);
+
+        mProtoCaptor = ArgumentCaptor.forClass(LogBuilder.class);
+        mNameCaptor = ArgumentCaptor.forClass(String.class);
+        mCountCaptor = ArgumentCaptor.forClass(Integer.class);
+
+        OngoingStubbing<LogBuilder> stub = when(mLogger.obtain()).thenReturn(mProto[0]);
+        for (int i = 1; i < mProto.length; i++) {
+            stub.thenReturn(mProto[i]);
+        }
+        doNothing().when(mLogger).addEvent(any(LogBuilder.class));
+        doNothing().when(mLogger).incrementBy(anyString(), anyInt());
+    }
+
+    protected void validateNotificationTimes(LogBuilder proto, int life, int freshness,
+            int exposure) {
+        validateNotificationTimes(proto, life, freshness);
+        if (exposure != 0) {
+            assertEquals(exposure,
+                proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
+        } else {
+            assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
+        }
+    }
+
+    protected void validateNotificationTimes(LogBuilder proto, int life, int freshness) {
+        if (life != 0) {
+            assertEquals(life,
+                proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
+        } else {
+            assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
+        }
+        if (freshness != 0) {
+            assertEquals(freshness,
+                proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
+        } else {
+            assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
+        }
+    }
+
+    protected void validateNotificationIdAndTag(LogBuilder proto, int id, String tag) {
+        assertEquals(tag, proto.getTaggedData(MetricsEvent.NOTIFICATION_TAG));
+        assertEquals(id, proto.getTaggedData(MetricsEvent.NOTIFICATION_ID));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/PowerScreenStateParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/PowerScreenStateParserTest.java
new file mode 100644
index 0000000..be918cd
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/PowerScreenStateParserTest.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.internal.logging.legacy;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class PowerScreenStateParserTest extends ParserTest {
+
+    public PowerScreenStateParserTest() {
+        mParser = new PowerScreenStateParser();
+    }
+
+    public void testScreenOn() throws Throwable {
+        validate(MetricsEvent.TYPE_OPEN, 0, "1,0,0,0");
+    }
+
+    public void testTimeout() throws Throwable {
+        validate(MetricsEvent.TYPE_CLOSE, 3, "0,3,0,0");
+    }
+
+    public void testUser() throws Throwable {
+        validate(MetricsEvent.TYPE_CLOSE, 2, "0,2,0,0");
+    }
+
+    public void testAdmin() throws Throwable {
+        validate(MetricsEvent.TYPE_CLOSE, 1, "0,1,0,0");
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        validate(MetricsEvent.TYPE_OPEN, 0, "1,0,0,0,5");
+    }
+
+    private void validate(int type, int subType, String log) {
+        String[] parts = log.split(",");
+        int t = 1000;
+        Object[] objects = new Object[parts.length];
+        for (int i = 0; i < parts.length; i++) {
+            objects[i] = Integer.valueOf(parts[i]);
+        }
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(type, proto.getType());
+        assertEquals(MetricsEvent.SCREEN, proto.getCategory());
+        assertEquals(subType, proto.getSubtype());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java
new file mode 100644
index 0000000..906ec04
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class StatusBarStateParserTest extends ParserTest {
+
+    public StatusBarStateParserTest() {
+        mParser = new StatusBarStateParser();
+    }
+
+    public void testLockScreen() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 1, "1,1,0,0,1,0");
+    }
+
+    public void testBounce() throws Throwable {
+        validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "1,1,0,1,1,0");
+    }
+
+    public void testUnlock() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_CLOSE, 1, "0,0,0,0,1,0");
+    }
+
+    public void testSecure() throws Throwable {
+        validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "2,1,0,1,1,0");
+    }
+
+    public void testInsecure() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0");
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0,5");
+    }
+
+    private void validate(int view, int type, int subType, String log) {
+        String[] parts = log.split(",");
+        int t = 1000;
+        Object[] objects = new Object[parts.length];
+        for (int i = 0; i < parts.length; i++) {
+            objects[i] = Integer.valueOf(parts[i]);
+        }
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(type, proto.getType());
+        assertEquals(subType, proto.getSubtype());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java
new file mode 100644
index 0000000..111909f
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class SysuiActionParserTest extends ParserTest {
+
+    public SysuiActionParserTest() {
+        mParser = new SysuiActionParser();
+    }
+
+    public void testGoodDatal() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[1];
+        objects[0] = view;
+
+        validateGoodData(t, view, objects);
+    }
+
+    private void validateGoodData(int t, int view, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testGoodDataWithPackage() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        String packageName = "com.foo";
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = packageName;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(packageName, proto.getPackageName());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testGoodDataWithTrue() throws Throwable {
+        validateSubType(Boolean.toString(true), 1);
+    }
+
+    public void testGoodDataWithFalse() throws Throwable {
+        validateSubType(Boolean.toString(false), 0);
+    }
+
+    public void testGoodDataWithIntZero() throws Throwable {
+        validateSubType(Integer.toString(0), 0);
+    }
+
+    public void testGoodDataWithIntONe() throws Throwable {
+        validateSubType(Integer.toString(1), 1);
+    }
+
+    public void testGoodDataWithIntTwo() throws Throwable {
+        validateSubType(Integer.toString(2), 2);
+    }
+
+    public void testGoodDataWithNegativeInt() throws Throwable {
+        validateSubType(Integer.toString(-1), -1);
+    }
+
+    public void testGoodDataWithIntLarge() throws Throwable {
+        validateSubType(Integer.toString(120312), 120312);
+    }
+
+    public void testGoodDataWithNegativeIntLarge() throws Throwable {
+        validateSubType(Integer.toString(-120312), -120312);
+    }
+
+    private void validateSubType(String arg, int expectedValue) {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = arg;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(expectedValue, proto.getSubtype());
+        assertNull(proto.getPackageName());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreWrongInputs() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "nothing to see here";
+        objects[1] = 10;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreStringViewInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "this is not the input you are looking for";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = "foo";
+
+        validateGoodData(t, view, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiMultiActionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiMultiActionParserTest.java
new file mode 100644
index 0000000..7853f77
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiMultiActionParserTest.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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class SysuiMultiActionParserTest extends ParserTest {
+
+    public SysuiMultiActionParserTest() {
+        mParser = new SysuiMultiActionParser();
+    }
+
+    public void testParseAllFields() {
+        int category = 10;
+        int type = 11;
+        int subtype = 12;
+        long timestamp = 1484669007890L;
+        String packageName = "com.foo.bar";
+        String counterName = "sheep";
+        int bucket = 13;
+        int value = 14;
+        LogBuilder builder = new LogBuilder(category);
+        builder.setType(type);
+        builder.setSubtype(subtype);
+        builder.setPackageName(packageName);
+        builder.setCounterName(counterName);
+        builder.setCounterBucket(bucket);
+        builder.setCounterValue(value);
+        builder.addTaggedData(1, "one");
+        builder.addTaggedData(2, "two");
+        Object[] out = builder.serialize();
+        int t = 1000;
+
+        mParser.parseEvent(mLogger, timestamp, out);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(category, proto.getCategory());
+        assertEquals(type, proto.getType());
+        assertEquals(subtype, proto.getSubtype());
+        assertEquals(timestamp, proto.getTimestamp());
+        assertEquals(packageName, proto.getPackageName());
+        assertEquals(counterName, proto.getCounterName());
+        assertEquals(bucket, proto.getCounterBucket());
+        assertEquals(value, proto.getCounterValue());
+        assertEquals("one", proto.getTaggedData(1));
+        assertEquals("two", proto.getTaggedData(2));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java
new file mode 100644
index 0000000..1291508
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class SysuiViewVisibilityParserTest extends ParserTest {
+
+    public SysuiViewVisibilityParserTest() {
+        mParser = new SysuiViewVisibilityParser();
+    }
+
+    public void testViewReveal() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = 100;
+
+        validateViewReveal(t, view, objects);
+    }
+
+    private void validateViewReveal(int t, int view, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+    }
+
+    public void testViewHidden() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = 0;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreStringInARgOne() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "nothing to see here";
+        objects[1] = 100;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreStringInArgTwo() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = 100;
+        objects[1] = "nothing to see here";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testOneInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 100;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[3];
+        objects[0] = view;
+        objects[1] = 100;
+        objects[2] = "foo";
+
+        validateViewReveal(t, view, objects);
+    }
+}
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
index 97e8b1f..47ee2cf 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver
+LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit legacy-android-test
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := DownloadManagerTestApp
diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk
index 702218c..0551eb6 100644
--- a/core/tests/notificationtests/Android.mk
+++ b/core/tests/notificationtests/Android.mk
@@ -12,6 +12,8 @@
 LOCAL_PACKAGE_NAME := NotificationStressTests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    junit \
+    legacy-android-test \
     ub-uiautomator
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/utillib/Android.mk b/core/tests/utillib/Android.mk
index 299ea5a..8811256 100644
--- a/core/tests/utillib/Android.mk
+++ b/core/tests/utillib/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_MODULE := frameworks-core-util-lib
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index 6718259..b2c6840 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -18,6 +18,14 @@
 
 ########################
 include $(CLEAR_VARS)
+LOCAL_MODULE := framework-sysconfig.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/sysconfig
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+########################
+include $(CLEAR_VARS)
 LOCAL_MODULE := platform.xml
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
@@ -31,4 +39,3 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
-
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
new file mode 100644
index 0000000..2f18de0
--- /dev/null
+++ b/data/etc/framework-sysconfig.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<!-- These are configurations that must exist on all Android devices. -->
+<config>
+
+    <!-- Broadcast actions that are currently exempted from O+ background
+         delivery restrictions. -->
+    <allow-implicit-broadcast action="android.intent.action.SIM_STATE_CHANGED" />
+    <allow-implicit-broadcast action="android.intent.action.PACKAGE_CHANGED" />
+
+</config>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 05db9b0..f1be4a9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -110,11 +110,21 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.omadm.service">
+        <permission name="android.permission.CHANGE_CONFIGURATION"/>
+        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.WRITE_APN_SETTINGS"/>
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.packageinstaller">
         <permission name="android.permission.CLEAR_APP_CACHE"/>
         <permission name="android.permission.DELETE_PACKAGES"/>
         <permission name="android.permission.INSTALL_PACKAGES"/>
         <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
     </privapp-permissions>
 
@@ -122,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_VISUAL_VOICEMAIL_SERVICE"/>
         <permission name="android.permission.CALL_PRIVILEGED"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
@@ -327,4 +338,4 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
-</permissions>
+</permissions>
\ No newline at end of file
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 77e8d77..021a07e 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -565,6 +565,38 @@
 method, which indicates whether the screen is round.</p>
       </td>
     </tr>
+    <tr id="WideColorGamutQualifier">
+      <td>Wide Color Gamut</td>
+      <td>
+        <code>widecg</code><br/>
+        <code>nowidecg</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code widecg}: Displays with a wide color gamut such as Display P3 or AdobeRGB</li>
+          <li>{@code nowidecg}: Displays with a narrow color gamut such as sRGB</li>
+        </ul>
+        <p><em>Added in API level 26.</em></p>
+        <p>Also see the {@link android.content.res.Configuration#isScreenWideColorGamut()} configuration
+        method, which indicates whether the screen has a wide color gamut.</p>
+      </td>
+    </tr>
+    <tr id="HDRQualifier">
+      <td>High Dynamic Range (HDR)</td>
+      <td>
+        <code>highdr</code><br/>
+        <code>lowdr</code>
+      </td>
+      <td>
+        <ul class="nolist">
+          <li>{@code highdr}: Displays with a high-dynamic range</li>
+          <li>{@code lowdr}: Displays with a low/standard dynamic range</li>
+        </ul>
+        <p><em>Added in API level 26.</em></p>
+        <p>Also see the {@link android.content.res.Configuration#isScreenHdr()} configuration
+        method, which indicates whether the screen has a HDR capabilities.</p>
+      </td>
+    </tr>
     <tr id="OrientationQualifier">
       <td>Screen orientation</td>
       <td>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index cc5cc7b..8572345 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -21,11 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
-import android.text.GraphicsOperations;
-import android.text.SpannableString;
-import android.text.SpannedString;
-import android.text.TextUtils;
 
+import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 import libcore.util.NativeAllocationRegistry;
@@ -501,8 +498,10 @@
      * an error to call restore() more times than save() was called.
      */
     public void restore() {
-        boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated();
-        nRestore(mNativeCanvasWrapper, throwOnUnderflow);
+        if (!nRestore(mNativeCanvasWrapper)
+                && (!sCompatibilityRestore || !isHardwareAccelerated())) {
+            throw new IllegalStateException("Underflow in restore - more restores than saves");
+        }
     }
 
     /**
@@ -527,8 +526,16 @@
      * @param saveCount The save level to restore to.
      */
     public void restoreToCount(int saveCount) {
-        boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated();
-        nRestoreToCount(mNativeCanvasWrapper, saveCount, throwOnUnderflow);
+        if (saveCount < 1) {
+            if (!sCompatibilityRestore || !isHardwareAccelerated()) {
+                // do nothing and throw without restoring
+                throw new IllegalArgumentException(
+                        "Underflow in restoreToCount - more restores than saves");
+            }
+            // compat behavior - restore as far as possible
+            saveCount = 1;
+        }
+        nRestoreToCount(mNativeCanvasWrapper, saveCount);
     }
 
     /**
@@ -643,7 +650,7 @@
      */
     @Deprecated
     public void getMatrix(@NonNull Matrix ctm) {
-        nGetCTM(mNativeCanvasWrapper, ctm.native_instance);
+        nGetMatrix(mNativeCanvasWrapper, ctm.native_instance);
     }
 
     /**
@@ -1059,79 +1066,66 @@
     // ---------------- @FastNative -------------------
 
     @FastNative
-    private static native void nSetBitmap(long canvasHandle,
-                                                Bitmap bitmap);
+    private static native void nSetBitmap(long canvasHandle, Bitmap bitmap);
+
     @FastNative
+    private static native boolean nGetClipBounds(long nativeCanvas, Rect bounds);
+
+    // ---------------- @CriticalNative -------------------
+
+    @CriticalNative
     private static native boolean nIsOpaque(long canvasHandle);
-    @FastNative
+    @CriticalNative
     private static native void nSetHighContrastText(long renderer, boolean highContrastText);
-    @FastNative
+    @CriticalNative
     private static native int nGetWidth(long canvasHandle);
-    @FastNative
+    @CriticalNative
     private static native int nGetHeight(long canvasHandle);
 
-    @FastNative
+    @CriticalNative
     private static native int nSave(long canvasHandle, int saveFlags);
-    @FastNative
-    private static native int nSaveLayer(long nativeCanvas, float l,
-                                               float t, float r, float b,
-                                               long nativePaint,
-                                               int layerFlags);
-    @FastNative
-    private static native int nSaveLayerAlpha(long nativeCanvas, float l,
-                                                    float t, float r, float b,
-                                                    int alpha, int layerFlags);
-    @FastNative
-    private static native void nRestore(long canvasHandle, boolean tolerateUnderflow);
-    @FastNative
-    private static native void nRestoreToCount(long canvasHandle,
-                                                     int saveCount,
-                                                     boolean tolerateUnderflow);
-    @FastNative
+    @CriticalNative
+    private static native int nSaveLayer(long nativeCanvas, float l, float t, float r, float b,
+            long nativePaint, int layerFlags);
+    @CriticalNative
+    private static native int nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b,
+            int alpha, int layerFlags);
+    @CriticalNative
+    private static native boolean nRestore(long canvasHandle);
+    @CriticalNative
+    private static native void nRestoreToCount(long canvasHandle, int saveCount);
+    @CriticalNative
     private static native int nGetSaveCount(long canvasHandle);
 
-    @FastNative
-    private static native void nTranslate(long canvasHandle,
-                                                float dx, float dy);
-    @FastNative
-    private static native void nScale(long canvasHandle,
-                                            float sx, float sy);
-    @FastNative
+    @CriticalNative
+    private static native void nTranslate(long canvasHandle, float dx, float dy);
+    @CriticalNative
+    private static native void nScale(long canvasHandle, float sx, float sy);
+    @CriticalNative
     private static native void nRotate(long canvasHandle, float degrees);
-    @FastNative
-    private static native void nSkew(long canvasHandle,
-                                           float sx, float sy);
-    @FastNative
-    private static native void nConcat(long nativeCanvas,
-                                             long nativeMatrix);
-    @FastNative
-    private static native void nSetMatrix(long nativeCanvas,
-                                                long nativeMatrix);
-    @FastNative
+    @CriticalNative
+    private static native void nSkew(long canvasHandle, float sx, float sy);
+    @CriticalNative
+    private static native void nConcat(long nativeCanvas, long nativeMatrix);
+    @CriticalNative
+    private static native void nSetMatrix(long nativeCanvas, long nativeMatrix);
+    @CriticalNative
     private static native boolean nClipRect(long nativeCanvas,
-                                                  float left, float top,
-                                                  float right, float bottom,
-                                                  int regionOp);
-    @FastNative
-    private static native boolean nClipPath(long nativeCanvas,
-                                                  long nativePath,
-                                                  int regionOp);
-    @FastNative
-    private static native void nSetDrawFilter(long nativeCanvas,
-                                                   long nativeFilter);
-    @FastNative
-    private static native boolean nGetClipBounds(long nativeCanvas,
-                                                       Rect bounds);
-    @FastNative
-    private static native void nGetCTM(long nativeCanvas,
-                                             long nativeMatrix);
-    @FastNative
-    private static native boolean nQuickReject(long nativeCanvas,
-                                                     long nativePath);
-    @FastNative
-    private static native boolean nQuickReject(long nativeCanvas,
-                                                     float left, float top,
-                                                     float right, float bottom);
+            float left, float top, float right, float bottom, int regionOp);
+    @CriticalNative
+    private static native boolean nClipPath(long nativeCanvas, long nativePath, int regionOp);
+    @CriticalNative
+    private static native void nSetDrawFilter(long nativeCanvas, long nativeFilter);
+    @CriticalNative
+    private static native void nGetMatrix(long nativeCanvas, long nativeMatrix);
+    @CriticalNative
+    private static native boolean nQuickReject(long nativeCanvas, long nativePath);
+    @CriticalNative
+    private static native boolean nQuickReject(long nativeCanvas, float left, float top,
+            float right, float bottom);
+
+
+    // ---------------- Draw Methods -------------------
 
     /**
      * <p>
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index a2c104a..ff21cac 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,27 +16,278 @@
 
 package android.graphics;
 
+import android.annotation.AnyThread;
 import android.annotation.ColorInt;
+import android.annotation.ColorLong;
+import android.annotation.HalfFloat;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Size;
 
+import android.util.Half;
 import com.android.internal.util.XmlUtils;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.function.DoubleUnaryOperator;
 
 /**
- * The Color class defines methods for creating and converting color ints.
- * Colors are represented as packed ints, made up of 4 bytes: alpha, red,
- * green, blue. The values are unpremultiplied, meaning any transparency is
- * stored solely in the alpha component, and not in the color components. The
- * components are stored as follows (alpha << 24) | (red << 16) |
- * (green << 8) | blue. Each component ranges between 0..255 with 0
- * meaning no contribution for that component, and 255 meaning 100%
- * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but
- * no contributions from red, green, or blue), and opaque-white would be
- * 0xFFFFFFFF
+ * {@usesMathJax}
+ *
+ * <p>The <code>Color</code> class provides methods for creating, converting and
+ * manipulating colors. Colors have three different representations:</p>
+ * <ul>
+ *     <li>Color ints, the most common representation</li>
+ *     <li>Color longs</li>
+ *     <li><code>Color</code> instances</li>
+ * </ul>
+ * <p>The section below describe each representation in detail.</p>
+ *
+ * <h3>Color ints</h3>
+ * <p>Color ints are the most common representation of colors on Android and
+ * have been used since {@link android.os.Build.VERSION_CODES#BASE API level 1}.</p>
+ *
+ * <p>A color int always defines a color in the {@link ColorSpace.Named#SRGB sRGB}
+ * color space using 4 components packed in a single 32 bit integer value:</p>
+ *
+ * <table summary="Color int definition">
+ *     <tr>
+ *         <th>Component</th><th>Name</th><th>Size</th><th>Range</th>
+ *     </tr>
+ *     <tr><td>A</td><td>Alpha</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>R</td><td>Red</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>G</td><td>Green</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>B</td><td>Blue</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ * </table>
+ *
+ * <p>The components in this table are listed in encoding order (see below),
+ * which is why color ints are called ARGB colors.</p>
+ *
+ * <h4>Usage in code</h4>
+ * <p>To avoid confusing color ints with arbitrary integer values, it is a
+ * good practice to annotate them with the <code>@ColorInt</code> annotation
+ * found in the Android Support Library.</p>
+ *
+ * <h4>Encoding</h4>
+ * <p>The four components of a color int are encoded in the following way:</p>
+ * <pre class="prettyprint">
+ * int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 16 | (B & 0xff);
+ * </pre>
+ *
+ * <p>Because of this encoding, color ints can easily be described as an integer
+ * constant in source. For instance, opaque blue is <code>0xff0000ff</code>
+ * and yellow is <code>0xffffff00</code>.</p>
+ *
+ * <p>To easily encode color ints, it is recommended to use the static methods
+ * {@link #argb(int, int, int, int)} and {@link #rgb(int, int, int)}. The second
+ * method omits the alpha component and assumes the color is opaque (alpha is 255).
+ * As a convenience this class also offers methods to encode color ints from components
+ * defined in the \([0..1]\) range: {@link #argb(float, float, float, float)} and
+ * {@link #rgb(float, float, float)}.</p>
+ *
+ * <p>Color longs (defined below) can be easily converted to color ints by invoking
+ * the {@link #toArgb(long)} method. This method performs a color space conversion
+ * if needed.</p>
+ *
+ * <p>It is also possible to create a color int by invoking the method {@link #toArgb()}
+ * on a color instance.</p>
+ *
+ * <h4>Decoding</h4>
+ * <p>The four ARGB components can be individually extracted from a color int
+ * using the following expressions:</p>
+ * <pre class="prettyprint">
+ * int A = (color >> 24) & 0xff; // or color >>> 24
+ * int R = (color >> 16) & 0xff;
+ * int G = (color >>  8) & 0xff;
+ * int B = (color      ) & 0xff;
+ * </pre>
+ *
+ * <p>This class offers convenience methods to easily extract these components:</p>
+ * <ul>
+ *     <li>{@link #alpha(int)} to extract the alpha component</li>
+ *     <li>{@link #red(int)} to extract the red component</li>
+ *     <li>{@link #green(int)} to extract the green component</li>
+ *     <li>{@link #blue(int)} to extract the blue component</li>
+ * </ul>
+ *
+ * <h3>Color longs</h3>
+ * <p>Color longs are a representation introduced in
+ * {@link android.os.Build.VERSION_CODES#O Android O} to store colors in different
+ * {@link ColorSpace color spaces}, with more precision than color ints.</p>
+ *
+ * <p>A color long always defines a color using 4 components packed in a single
+ * 64 bit long value. One of these components is always alpha while the other
+ * three components depend on the color space's {@link ColorSpace.Model color model}.
+ * The most common color model is the {@link ColorSpace.Model#RGB RGB} model in
+ * which the components represent red, green and blue values.</p>
+ *
+ * <p class="note"><b>Component ranges:</b> the ranges defined in the tables
+ * below indicate the ranges that can be encoded in a color long. They do not
+ * represent the actual ranges as they may differ per color space. For instance,
+ * the RGB components of a color in the {@link ColorSpace.Named#DISPLAY_P3 Display P3}
+ * color space use the \([0..1]\) range. Please refer to the documentation of the
+ * various {@link ColorSpace.Named color spaces} to find their respective ranges.</p>
+ *
+ * <p class="note"><b>Alpha range:</b> while alpha is encoded in a color long using
+ * a 10 bit integer (thus using a range of \([0..1023]\)), it is converted to and
+ * from \([0..1]\) float values when decoding and encoding color longs.</p>
+ *
+ * <p class="note"><b>sRGB color space:</b> for compatibility reasons and ease of
+ * use, color longs encoding {@link ColorSpace.Named#SRGB sRGB} colors do not
+ * use the same encoding as other color longs.</p>
+ *
+ * <table summary="Color long definition">
+ *     <tr>
+ *         <th>Component</th><th>Name</th><th>Size</th><th>Range</th>
+ *     </tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#RGB RGB} color model</td></tr>
+ *     <tr><td>R</td><td>Red</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>G</td><td>Green</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>B</td><td>Blue</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr>
+ *     <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Named#SRGB sRGB} color space</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>R</td><td>Red</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>G</td><td>Green</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>B</td><td>Blue</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>X</td><td>Unused</td><td>32 bits</td><td>\(0\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#XYZ XYZ} color model</td></tr>
+ *     <tr><td>X</td><td>X</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>Y</td><td>Y</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>Z</td><td>Z</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr>
+ *     <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#XYZ Lab} color model</td></tr>
+ *     <tr><td>L</td><td>L</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>a</td><td>a</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>b</td><td>b</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr>
+ *     <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#CMYK CMYK} color model</td></tr>
+ *     <tr><td colspan="4">Unsupported</td></tr>
+ * </table>
+ *
+ * <p>The components in this table are listed in encoding order (see below),
+ * which is why color longs in the RGB model are called RGBA colors (even if
+ * this doesn't quite hold for the special case of sRGB colors).</p>
+ *
+ * <p>The color long encoding relies on half-precision float values (fp16). If you
+ * wish to know more about the limitations of half-precision float values, please
+ * refer to the documentation of the {@link Half} class.</p>
+ *
+ * <h4>Usage in code</h4>
+ * <p>To avoid confusing color longs with arbitrary long values, it is a
+ * good practice to annotate them with the <code>@ColorLong</code> annotation
+ * found in the Android Support Library.</p>
+ *
+ * <h4>Encoding</h4>
+ *
+ * <p>Given the complex nature of color longs, it is strongly encouraged to use
+ * the various methods provided by this class to encode them.</p>
+ *
+ * <p>The most flexible way to encode a color long is to use the method
+ * {@link #pack(float, float, float, float, ColorSpace)}. This method allows you
+ * to specify three color components (typically RGB), an alpha component and a
+ * color space. To encode sRGB colors, use {@link #pack(float, float, float)}
+ * and {@link #pack(float, float, float, float)} which are the
+ * equivalent of {@link #rgb(int, int, int)} and {@link #argb(int, int, int, int)}
+ * for color ints. If you simply need to convert a color int into a color long,
+ * use {@link #pack(int)}.</p>
+ *
+ * <p>It is also possible to create a color long value by invoking the method
+ * {@link #pack()} on a color instance.</p>
+ *
+ * <h4>Decoding</h4>
+ *
+ * <p>This class offers convenience methods to easily extract the components
+ * of a color long:</p>
+ * <ul>
+ *     <li>{@link #alpha(long)} to extract the alpha component</li>
+ *     <li>{@link #red(long)} to extract the red/X/L component</li>
+ *     <li>{@link #green(long)} to extract the green/Y/a component</li>
+ *     <li>{@link #blue(long)} to extract the blue/Z/b component</li>
+ * </ul>
+ *
+ * <p>The values returned by these methods depend on the color space encoded
+ * in the color long. The values are however typically in the \([0..1]\) range
+ * for RGB colors. Please refer to the documentation of the various
+ * {@link ColorSpace.Named color spaces} for the exact ranges.</p>
+ *
+ * <h3>Color instances</h3>
+ * <p>Color instances are a representation introduced in
+ * {@link android.os.Build.VERSION_CODES#O Android O} to store colors in different
+ * {@link ColorSpace color spaces}, with more precision than both color ints and
+ * color longs. Color instances also offer the ability to store more than 4
+ * components if necessary.</p>
+ *
+ * <p>Colors instances are immutable and can be created using one of the various
+ * <code>valueOf</code> methods. For instance:</p>
+ * <pre class="prettyprint">
+ * // sRGB
+ * Color opaqueRed = Color.valueOf(0xffff0000); // from a color int
+ * Color translucentRed = Color.valueOf(1.0f, 0.0f, 0.0f, 0.5f);
+ *
+ * // Wide gamut color
+ * {@literal @}ColorLong long p3 = pack(1.0f, 1.0f, 0.0f, 1.0f, colorSpaceP3);
+ * Color opaqueYellow = Color.valueOf(p3); // from a color long
+ *
+ * // CIE L*a*b* color space
+ * ColorSpace lab = ColorSpace.get(ColorSpace.Named.LAB);
+ * Color green = Color.valueOf(100.0f, -128.0f, 128.0f, 1.0f, lab);
+ * </pre>
+ *
+ * <p>Color instances can be converted to color ints ({@link #toArgb()}) or
+ * color longs ({@link #pack()}). They also offer easy access to their various
+ * components using the following methods:</p>
+ * <ul>
+ *     <li>{@link #alpha()}, returns the alpha component value</li>
+ *     <li>{@link #red()}, returns the red component value (or first
+ *     component value in non-RGB models)</li>
+ *     <li>{@link #green()}, returns the green component value (or second
+ *     component value in non-RGB models)</li>
+ *     <li>{@link #blue()}, returns the blue component value (or third
+ *     component value in non-RGB models)</li>
+ *     <li>{@link #getComponent(int)}, returns a specific component value</li>
+ *     <li>{@link #getComponents()}, returns all component values as an array</li>
+ * </ul>
+ *
+ * <h3>Color space conversions</h3>
+ * <p>You can convert colors from one color space to another using
+ * {@link ColorSpace#connect(ColorSpace, ColorSpace)} and its variants. However,
+ * the <code>Color</code> class provides a few convenience methods to simplify
+ * the process. Here is a brief description of some of them:</p>
+ * <ul>
+ *     <li>{@link #convert(ColorSpace)} to convert a color instance in a color
+ *     space to a new color instance in a different color space</li>
+ *     <li>{@link #convert(float, float, float, float, ColorSpace, ColorSpace)} to
+ *     convert a color from a source color space to a destination color space</li>
+ *     <li>{@link #convert(long, ColorSpace)} to convert a color long from its
+ *     built-in color space to a destination color space</li>
+ *     <li>{@link #convert(int, ColorSpace)} to convert a color int from sRGB
+ *     to a destination color space</li>
+ * </ul>
+ *
+ * <p>Please refere to the {@link ColorSpace} documentation for more
+ * information.</p>
+ *
+ * <h3>Alpha and transparency</h3>
+ * <p>The alpha component of a color defines the level of transparency of a
+ * color. When the alpha component is 0, the color is completely transparent.
+ * When the alpha is component is 1 (in the \([0..1]\) range) or 255 (in the
+ * \([0..255]\) range), the color is completely opaque.</p>
+ *
+ * <p>The color representations described above do not use pre-multiplied
+ * color components (a pre-multiplied color component is a color component
+ * that has been multiplied by the value of the alpha component).
+ * For instance, the color int representation of opaque red is
+ * <code>0xffff0000</code>. For semi-transparent (50%) red, the
+ * representation becomes <code>0x80ff0000</code>. The equivalent color
+ * instance representations would be <code>(1.0, 0.0, 0.0, 1.0)</code>
+ * and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p>
  */
+@AnyThread
 public class Color {
     @ColorInt public static final int BLACK       = 0xFF000000;
     @ColorInt public static final int DKGRAY      = 0xFF444444;
@@ -51,10 +302,905 @@
     @ColorInt public static final int MAGENTA     = 0xFFFF00FF;
     @ColorInt public static final int TRANSPARENT = 0;
 
+    @NonNull
+    @Size(min = 4, max = 5)
+    private final float[] mComponents;
+
+    @NonNull
+    private final ColorSpace mColorSpace;
+
+    /**
+     * Creates a new color instance set to opaque black in the
+     * {@link ColorSpace.Named#SRGB sRGB} color space.
+     *
+     * @see #valueOf(float, float, float)
+     * @see #valueOf(float, float, float, float)
+     * @see #valueOf(float, float, float, float, ColorSpace)
+     * @see #valueOf(float[], ColorSpace)
+     * @see #valueOf(int)
+     * @see #valueOf(long)
+     */
+    public Color() {
+        // This constructor is required for compatibility with previous APIs
+        mComponents = new float[] { 0.0f, 0.0f, 0.0f, 1.0f };
+        mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+    }
+
+    /**
+     * Creates a new color instance in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @param r The value of the red channel, must be in [0..1] range
+     * @param g The value of the green channel, must be in [0..1] range
+     * @param b The value of the blue channel, must be in [0..1] range
+     * @param a The value of the alpha channel, must be in [0..1] range
+     */
+    private Color(float r, float g, float b, float a) {
+        this(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * Creates a new color instance in the specified color space. The color space
+     * must have a 3 components model.
+     *
+     * @param r The value of the red channel, must be in the color space defined range
+     * @param g The value of the green channel, must be in the color space defined range
+     * @param b The value of the blue channel, must be in the color space defined range
+     * @param a The value of the alpha channel, must be in [0..1] range
+     * @param colorSpace This color's color space, cannot be null
+     */
+    private Color(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) {
+        mComponents = new float[] { r, g, b, a };
+        mColorSpace = colorSpace;
+    }
+
+    /**
+     * Creates a new color instance in the specified color space.
+     *
+     * @param components An array of color components, plus alpha
+     * @param colorSpace This color's color space, cannot be null
+     */
+    private Color(@Size(min = 4, max = 5) float[] components, @NonNull ColorSpace colorSpace) {
+        mComponents = components;
+        mColorSpace = colorSpace;
+    }
+
+    /**
+     * Returns this color's color space.
+     *
+     * @return A non-null instance of {@link ColorSpace}
+     */
+    @NonNull
+    public ColorSpace getColorSpace() {
+        return mColorSpace;
+    }
+
+    /**
+     * Returns the color model of this color.
+     *
+     * @return A non-null {@link ColorSpace.Model}
+     */
+    public ColorSpace.Model getModel() {
+        return mColorSpace.getModel();
+    }
+
+    /**
+     * Indicates whether this color color is in a wide-gamut color space.
+     * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut
+     * color space.
+     *
+     * @return True if this color is in a wide-gamut color space, false otherwise
+     *
+     * @see #isSrgb()
+     * @see ColorSpace#isWideGamut()
+     */
+    public boolean isWideGamut() {
+        return getColorSpace().isWideGamut();
+    }
+
+    /**
+     * Indicates whether this color is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @return True if this color is in the sRGB color space, false otherwise
+     *
+     * @see #isWideGamut()
+     */
+    public boolean isSrgb() {
+        return getColorSpace().isSrgb();
+    }
+
+    /**
+     * Returns the number of components that form a color value according
+     * to this color space's color model, plus one extra component for
+     * alpha.
+     *
+     * @return An integer between 4 and 5
+     */
+    @IntRange(from = 4, to = 5)
+    public int getComponentCount() {
+        return mColorSpace.getComponentCount() + 1;
+    }
+
+    /**
+     * Packs this color into a color long. See the documentation of this class
+     * for a description of the color long format.
+     *
+     * @return A color long
+     *
+     * @throws IllegalArgumentException If this color's color space has the id
+     * {@link ColorSpace#MIN_ID} or if this color has more than 4 components
+     */
+    @ColorLong
+    public long pack() {
+        return pack(mComponents[0], mComponents[1], mComponents[2], mComponents[3], mColorSpace);
+    }
+
+    /**
+     * Converts this color from its color space to the specified color space.
+     * The conversion is done using the default rendering intent as specified
+     * by {@link ColorSpace#connect(ColorSpace, ColorSpace)}.
+     *
+     * @param colorSpace The destination color space, cannot be null
+     *
+     * @return A non-null color instance in the specified color space
+     */
+    @NonNull
+    public Color convert(@NonNull ColorSpace colorSpace) {
+        ColorSpace.Connector connector = ColorSpace.connect(mColorSpace, colorSpace);
+        float[] color = new float[] {
+                mComponents[0], mComponents[1], mComponents[2], mComponents[3]
+        };
+        connector.transform(color);
+        return new Color(color, colorSpace);
+    }
+
+    /**
+     * Converts this color to an ARGB color int. A color int is always in
+     * the {@link ColorSpace.Named#SRGB sRGB} color space. This implies
+     * a color space conversion is applied if needed.
+     *
+     * @return An ARGB color in the sRGB color space
+     */
+    @ColorInt
+    public int toArgb() {
+        if (mColorSpace.isSrgb()) {
+            return ((int) (mComponents[3] * 255.0f + 0.5f) << 24) |
+                   ((int) (mComponents[0] * 255.0f + 0.5f) << 16) |
+                   ((int) (mComponents[1] * 255.0f + 0.5f) <<  8) |
+                    (int) (mComponents[2] * 255.0f + 0.5f);
+        }
+
+        float[] color = new float[] {
+                mComponents[0], mComponents[1], mComponents[2], mComponents[3]
+        };
+        // The transformation saturates the output
+        ColorSpace.connect(mColorSpace).transform(color);
+
+        return ((int) (color[3] * 255.0f + 0.5f) << 24) |
+               ((int) (color[0] * 255.0f + 0.5f) << 16) |
+               ((int) (color[1] * 255.0f + 0.5f) <<  8) |
+                (int) (color[2] * 255.0f + 0.5f);
+    }
+
+    /**
+     * <p>Returns the value of the red component in the range defined by this
+     * color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB},
+     * calling this method is equivalent to <code>getComponent(0)</code>.</p>
+     *
+     * @see #alpha()
+     * @see #red()
+     * @see #green
+     * @see #getComponents()
+     */
+    public float red() {
+        return mComponents[0];
+    }
+
+    /**
+     * <p>Returns the value of the green component in the range defined by this
+     * color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB},
+     * calling this method is equivalent to <code>getComponent(1)</code>.</p>
+     *
+     * @see #alpha()
+     * @see #red()
+     * @see #green
+     * @see #getComponents()
+     */
+    public float green() {
+        return mComponents[1];
+    }
+
+    /**
+     * <p>Returns the value of the blue component in the range defined by this
+     * color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB},
+     * calling this method is equivalent to <code>getComponent(2)</code>.</p>
+     *
+     * @see #alpha()
+     * @see #red()
+     * @see #green
+     * @see #getComponents()
+     */
+    public float blue() {
+        return mComponents[2];
+    }
+
+    /**
+     * Returns the value of the alpha component in the range \([0..1]\).
+     * Calling this method is equivalent to
+     * <code>getComponent(getComponentCount())</code>.
+     *
+     * @see #red()
+     * @see #green()
+     * @see #blue()
+     * @see #getComponents()
+     * @see #getComponent(int)
+     */
+    public float alpha() {
+        return mComponents[mComponents.length - 1];
+    }
+
+    /**
+     * Returns this color's components as a new array. The last element of the
+     * array is always the alpha component.
+     *
+     * @return A new, non-null array whose size is equal to {@link #getComponentCount()}
+     *
+     * @see #getComponent(int)
+     */
+    @NonNull
+    @Size(min = 4, max = 5)
+    public float[] getComponents() {
+        return Arrays.copyOf(mComponents, mColorSpace.getComponentCount() + 1);
+    }
+
+    /**
+     * <p>Returns the value of the specified component in the range defined by
+     * this color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If the requested component index is {@link #getComponentCount()},
+     * this method returns the alpha component, always in the range
+     * \([0..1\).</p>
+     *
+     * @see #getComponents()
+     *
+     * @throws ArrayIndexOutOfBoundsException If the specified component index
+     * is < 0 or >= {@link #getComponentCount()}
+     */
+    public float getComponent(@IntRange(from = 0, to = 4) int component) {
+        return mComponents[component];
+    }
+
+    /**
+     * <p>Returns the relative luminance of this color.</p>
+     *
+     * <p>Based on the formula for relative luminance defined in WCAG 2.0,
+     * W3C Recommendation 11 December 2008.</p>
+     *
+     * @return A value between 0 (darkest black) and 1 (lightest white)
+     *
+     * @throws IllegalArgumentException If the this color's color space
+     * does not use the {@link ColorSpace.Model#RGB RGB} color model
+     */
+    public float luminance() {
+        if (mColorSpace.getModel() != ColorSpace.Model.RGB) {
+            throw new IllegalArgumentException("The specified color must be encoded in an RGB " +
+                    "color space. The supplied color space is " + mColorSpace.getModel());
+        }
+
+        DoubleUnaryOperator eotf = ((ColorSpace.Rgb) mColorSpace).getEotf();
+        double r = eotf.applyAsDouble(mComponents[0]);
+        double g = eotf.applyAsDouble(mComponents[1]);
+        double b = eotf.applyAsDouble(mComponents[2]);
+
+        return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b)));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Color color = (Color) o;
+
+        //noinspection SimplifiableIfStatement
+        if (!Arrays.equals(mComponents, color.mComponents)) return false;
+        return mColorSpace.equals(color.mColorSpace);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Arrays.hashCode(mComponents);
+        result = 31 * result + mColorSpace.hashCode();
+        return result;
+    }
+
+    /**
+     * <p>Returns a string representation of the object. This method returns
+     * a string equal to the value of:</p>
+     *
+     * <pre class="prettyprint">
+     * "Color(" + r + ", " + g + ", " + b + ", " + a +
+     *         ", " + getColorSpace().getName + ')'
+     * </pre>
+     *
+     * <p>For instance, the string representation of opaque black in the sRGB
+     * color space is equal to the following value:</p>
+     *
+     * <pre>
+     * Color(0.0, 0.0, 0.0, 1.0, sRGB IEC61966-2.1)
+     * </pre>
+     *
+     * @return A non-null string representation of the object
+     */
+    @Override
+    @NonNull
+    public String toString() {
+        StringBuilder b = new StringBuilder("Color(");
+        for (float c : mComponents) {
+            b.append(c).append(", ");
+        }
+        b.append(mColorSpace.getName());
+        b.append(')');
+        return b.toString();
+    }
+
+    /**
+     * Returns the color space encoded in the specified color long.
+     *
+     * @param color The color long whose color space to extract
+     * @return A non-null color space instance. If the color long encodes
+     * an unknown or invalid color space, the {@link ColorSpace.Named#SRGB sRGB}
+     * color space is returned
+     *
+     * @see #red(long)
+     * @see #green(long)
+     * @see #blue(long)
+     * @see #alpha(long)
+     */
+    @NonNull
+    public static ColorSpace colorSpace(@ColorLong long color) {
+        return ColorSpace.get((int) (color & 0x3fL));
+    }
+
+    /**
+     * Returns the red component encoded in the specified color long.
+     * The range of the returned value depends on the color space
+     * associated with the specified color. The color space can be
+     * queried by calling {@link #colorSpace(long)}.
+     *
+     * @param color The color long whose red channel to extract
+     * @return A float value with a range defined by the specified color's
+     * color space
+     *
+     * @see #colorSpace(long)
+     * @see #green(long)
+     * @see #blue(long)
+     * @see #alpha(long)
+     */
+    public static float red(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 48) & 0xff) / 255.0f;
+        return Half.toFloat((short) ((color >> 48) & 0xffff));
+    }
+
+    /**
+     * Returns the green component encoded in the specified color long.
+     * The range of the returned value depends on the color space
+     * associated with the specified color. The color space can be
+     * queried by calling {@link #colorSpace(long)}.
+     *
+     * @param color The color long whose green channel to extract
+     * @return A float value with a range defined by the specified color's
+     * color space
+     *
+     * @see #colorSpace(long)
+     * @see #red(long)
+     * @see #blue(long)
+     * @see #alpha(long)
+     */
+    public static float green(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 40) & 0xff) / 255.0f;
+        return Half.toFloat((short) ((color >> 32) & 0xffff));
+    }
+
+    /**
+     * Returns the blue component encoded in the specified color long.
+     * The range of the returned value depends on the color space
+     * associated with the specified color. The color space can be
+     * queried by calling {@link #colorSpace(long)}.
+     *
+     * @param color The color long whose blue channel to extract
+     * @return A float value with a range defined by the specified color's
+     * color space
+     *
+     * @see #colorSpace(long)
+     * @see #red(long)
+     * @see #green(long)
+     * @see #alpha(long)
+     */
+    public static float blue(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 32) & 0xff) / 255.0f;
+        return Half.toFloat((short) ((color >> 16) & 0xffff));
+    }
+
+    /**
+     * Returns the alpha component encoded in the specified color long.
+     * The returned value is always in the range \([0..1]\).
+     *
+     * @param color The color long whose blue channel to extract
+     * @return A float value in the range \([0..1]\)
+     *
+     * @see #colorSpace(long)
+     * @see #red(long)
+     * @see #green(long)
+     * @see #blue(long)
+     */
+    public static float alpha(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 56) & 0xff) / 255.0f;
+        return ((color >> 6) & 0x3ff) / 1023.0f;
+    }
+
+    /**
+     * Indicates whether the specified color is in the
+     * {@link ColorSpace.Named#SRGB sRGB} color space.
+     *
+     * @param color The color to test
+     * @return True if the color is in the sRGB color space, false otherwise
+     *
+     * @see #isInColorSpace(long, ColorSpace)
+     * @see #isWideGamut(long)
+     */
+    public static boolean isSrgb(@ColorLong long color) {
+        return colorSpace(color).isSrgb();
+    }
+
+    /**
+     * Indicates whether the specified color is in a wide-gamut color space.
+     * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut
+     * color space.
+     *
+     * @param color The color to test
+     * @return True if the color is in a wide-gamut color space, false otherwise
+     *
+     * @see #isInColorSpace(long, ColorSpace)
+     * @see #isSrgb(long)
+     * @see ColorSpace#isWideGamut()
+     */
+    public static boolean isWideGamut(@ColorLong long color) {
+        return colorSpace(color).isWideGamut();
+    }
+
+    /**
+     * Indicates whether the specified color is in the specified color space.
+     *
+     * @param color The color to test
+     * @param colorSpace The color space to test against
+     * @return True if the color is in the specified color space, false otherwise
+     *
+     * @see #isSrgb(long)
+     * @see #isWideGamut(long)
+     */
+    public static boolean isInColorSpace(@ColorLong long color, @NonNull ColorSpace colorSpace) {
+        return (int) (color & 0x3fL) == colorSpace.getId();
+    }
+
+    /**
+     * Converts the specified color long to an ARGB color int. A color int is
+     * always in the {@link ColorSpace.Named#SRGB sRGB} color space. This implies
+     * a color space conversion is applied if needed.
+     *
+     * @return An ARGB color in the sRGB color space
+     */
+    @ColorInt
+    public static int toArgb(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return (int) (color >> 32);
+
+        float r = red(color);
+        float g = green(color);
+        float b = blue(color);
+        float a = alpha(color);
+
+        // The transformation saturates the output
+        float[] c = ColorSpace.connect(colorSpace(color)).transform(r, g, b);
+
+        return ((int) (a    * 255.0f + 0.5f) << 24) |
+               ((int) (c[0] * 255.0f + 0.5f) << 16) |
+               ((int) (c[1] * 255.0f + 0.5f) <<  8) |
+                (int) (c[2] * 255.0f + 0.5f);
+    }
+
+    /**
+     * Creates a new <code>Color</code> instance from an ARGB color int.
+     * The resulting color is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @param color The ARGB color int to create a <code>Color</code> from
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(@ColorInt int color) {
+        float r = ((color >> 16) & 0xff) / 255.0f;
+        float g = ((color >>  8) & 0xff) / 255.0f;
+        float b = ((color      ) & 0xff) / 255.0f;
+        float a = ((color >> 24) & 0xff) / 255.0f;
+        return new Color(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * Creates a new <code>Color</code> instance from a color long.
+     * The resulting color is in the same color space as the specified color long.
+     *
+     * @param color The color long to create a <code>Color</code> from
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(@ColorLong long color) {
+        return new Color(red(color), green(color), blue(color), alpha(color), colorSpace(color));
+    }
+
+    /**
+     * Creates a new opaque <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space with the specified red, green and blue component values. The component
+     * values must be in the range \([0..1]\).
+     *
+     * @param r The red component of the opaque sRGB color to create, in \([0..1]\)
+     * @param g The green component of the opaque sRGB color to create, in \([0..1]\)
+     * @param b The blue component of the opaque sRGB color to create, in \([0..1]\)
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(float r, float g, float b) {
+        return new Color(r, g, b, 1.0f);
+    }
+
+    /**
+     * Creates a new <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space with the specified red, green, blue and alpha component values.
+     * The component values must be in the range \([0..1]\).
+     *
+     * @param r The red component of the sRGB color to create, in \([0..1]\)
+     * @param g The green component of the sRGB color to create, in \([0..1]\)
+     * @param b The blue component of the sRGB color to create, in \([0..1]\)
+     * @param a The alpha component of the sRGB color to create, in \([0..1]\)
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(float r, float g, float b, float a) {
+        return new Color(saturate(r), saturate(g), saturate(b), saturate(a));
+    }
+
+    /**
+     * Creates a new <code>Color</code> in the specified color space with the
+     * specified red, green, blue and alpha component values. The range of the
+     * components is defined by {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}. The values passed to this method
+     * must be in the proper range.
+     *
+     * @param r The red component of the color to create
+     * @param g The green component of the color to create
+     * @param b The blue component of the color to create
+     * @param a The alpha component of the color to create, in \([0..1]\)
+     * @param colorSpace The color space of the color to create
+     * @return A non-null instance of {@link Color}
+     *
+     * @throws IllegalArgumentException If the specified color space uses a
+     * color model with more than 3 components
+     */
+    @NonNull
+    public static Color valueOf(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) {
+        if (colorSpace.getComponentCount() > 3) {
+            throw new IllegalArgumentException("The specified color space must use a color model " +
+                    "with at most 3 color components");
+        }
+        return new Color(r, g, b, a, colorSpace);
+    }
+
+    /**
+     * <p>Creates a new <code>Color</code> in the specified color space with the
+     * specified component values. The range of the components is defined by
+     * {@link ColorSpace#getMinValue(int)} and {@link ColorSpace#getMaxValue(int)}.
+     * The values passed to this method must be in the proper range. The alpha
+     * component is always in the range \([0..1]\).</p>
+     *
+     * <p>The length of the array of components must be at least
+     * <code>{@link ColorSpace#getComponentCount()} + 1</code>. The component at index
+     * {@link ColorSpace#getComponentCount()} is always alpha.</p>
+     *
+     * @param components The components of the color to create, with alpha as the last component
+     * @param colorSpace The color space of the color to create
+     * @return A non-null instance of {@link Color}
+     *
+     * @throws IllegalArgumentException If the array of components is smaller than
+     * required by the color space
+     */
+    @NonNull
+    public static Color valueOf(@NonNull @Size(min = 4, max = 5) float[] components,
+            @NonNull ColorSpace colorSpace) {
+        if (components.length < colorSpace.getComponentCount() + 1) {
+            throw new IllegalArgumentException("Received a component array of length " +
+                    components.length + " but the color model requires " +
+                    (colorSpace.getComponentCount() + 1) + " (including alpha)");
+        }
+        return new Color(Arrays.copyOf(components, colorSpace.getComponentCount() + 1), colorSpace);
+    }
+
+    /**
+     * Converts the specified ARGB color int to an RGBA color long in the sRGB
+     * color space. See the documentation of this class for a description of
+     * the color long format.
+     *
+     * @param color The ARGB color int to convert to an RGBA color long in sRGB
+     *
+     * @return A color long
+     */
+    @ColorLong
+    public static long pack(@ColorInt int color) {
+        return (color & 0xffffffffL) << 32;
+    }
+
+    /**
+     * Packs the sRGB color defined by the specified red, green and blue component
+     * values into an RGBA color long in the sRGB color space. The alpha component
+     * is set to 1.0. See the documentation of this class for a description of the
+     * color long format.
+     *
+     * @param red The red component of the sRGB color to create, in \([0..1]\)
+     * @param green The green component of the sRGB color to create, in \([0..1]\)
+     * @param blue The blue component of the sRGB color to create, in \([0..1]\)
+     *
+     * @return A color long
+     */
+    @ColorLong
+    public static long pack(float red, float green, float blue) {
+        return pack(red, green, blue, 1.0f, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * Packs the sRGB color defined by the specified red, green, blue and alpha
+     * component values into an RGBA color long in the sRGB color space. See the
+     * documentation of this class for a description of the color long format.
+     *
+     * @param red The red component of the sRGB color to create, in \([0..1]\)
+     * @param green The green component of the sRGB color to create, in \([0..1]\)
+     * @param blue The blue component of the sRGB color to create, in \([0..1]\)
+     * @param alpha The alpha component of the sRGB color to create, in \([0..1]\)
+     *
+     * @return A color long
+     */
+    @ColorLong
+    public static long pack(float red, float green, float blue, float alpha) {
+        return pack(red, green, blue, alpha, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * <p>Packs the 3 component color defined by the specified red, green, blue and
+     * alpha component values into a color long in the specified color space. See the
+     * documentation of this class for a description of the color long format.</p>
+     *
+     * <p>The red, green and blue components must be in the range defined by the
+     * specified color space. See {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}.</p>
+     *
+     * @param red The red component of the color to create
+     * @param green The green component of the color to create
+     * @param blue The blue component of the color to create
+     * @param alpha The alpha component of the color to create, in \([0..1]\)
+     *
+     * @return A color long
+     *
+     * @throws IllegalArgumentException If the color space's id is {@link ColorSpace#MIN_ID}
+     * or if the color space's color model has more than 3 components
+     */
+    @ColorLong
+    public static long pack(float red, float green, float blue, float alpha,
+            @NonNull ColorSpace colorSpace) {
+        if (colorSpace.isSrgb()) {
+            int argb =
+                    ((int) (alpha * 255.0f + 0.5f) << 24) |
+                    ((int) (red   * 255.0f + 0.5f) << 16) |
+                    ((int) (green * 255.0f + 0.5f) <<  8) |
+                     (int) (blue  * 255.0f + 0.5f);
+            return (argb & 0xffffffffL) << 32;
+        }
+
+        int id = colorSpace.getId();
+        if (id == ColorSpace.MIN_ID) {
+            throw new IllegalArgumentException(
+                    "Unknown color space, please use a color space returned by ColorSpace.get()");
+        }
+        if (colorSpace.getComponentCount() > 3) {
+            throw new IllegalArgumentException(
+                    "The color space must use a color model with at most 3 components");
+        }
+
+        @HalfFloat short r = Half.valueOf(red);
+        @HalfFloat short g = Half.valueOf(green);
+        @HalfFloat short b = Half.valueOf(blue);
+
+        int a = (int) (Math.max(0.0f, Math.min(alpha, 1.0f)) * 1023.0f + 0.5f);
+
+        // Suppress sign extension
+        return  (r & 0xffffL) << 48 |
+                (g & 0xffffL) << 32 |
+                (b & 0xffffL) << 16 |
+                (a & 0x3ffL ) <<  6 |
+                id & 0x3fL;
+    }
+
+    /**
+     * Converts the specified ARGB color int from the {@link ColorSpace.Named#SRGB sRGB}
+     * color space into the specified destination color space. The resulting color is
+     * returned as a color long. See the documentation of this class for a description
+     * of the color long format.
+     *
+     * @param color The sRGB color int to convert
+     * @param colorSpace The destination color space
+     * @return A color long in the destination color space
+     */
+    @ColorLong
+    public static long convert(@ColorInt int color, @NonNull ColorSpace colorSpace) {
+        float r = ((color >> 16) & 0xff) / 255.0f;
+        float g = ((color >>  8) & 0xff) / 255.0f;
+        float b = ((color      ) & 0xff) / 255.0f;
+        float a = ((color >> 24) & 0xff) / 255.0f;
+        ColorSpace source = ColorSpace.get(ColorSpace.Named.SRGB);
+        return convert(r, g, b, a, source, colorSpace);
+    }
+
+    /**
+     * <p>Converts the specified color long from its color space into the specified
+     * destination color space. The resulting color is returned as a color long. See
+     * the documentation of this class for a description of the color long format.</p>
+     *
+     * <p>When converting several colors in a row, it is recommended to use
+     * {@link #convert(long, ColorSpace.Connector)} instead to
+     * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p>
+     *
+     * @param color The color long to convert
+     * @param colorSpace The destination color space
+     * @return A color long in the destination color space
+     */
+    @ColorLong
+    public static long convert(@ColorLong long color, @NonNull ColorSpace colorSpace) {
+        float r = red(color);
+        float g = green(color);
+        float b = blue(color);
+        float a = alpha(color);
+        ColorSpace source = colorSpace(color);
+        return convert(r, g, b, a, source, colorSpace);
+    }
+
+    /**
+     * <p>Converts the specified 3 component color from the source color space to the
+     * destination color space. The resulting color is returned as a color long. See
+     * the documentation of this class for a description of the color long format.</p>
+     *
+     * <p>When converting multiple colors in a row, it is recommended to use
+     * {@link #convert(float, float, float, float, ColorSpace.Connector)} instead to
+     * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p>
+     *
+     * <p>The red, green and blue components must be in the range defined by the
+     * specified color space. See {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}.</p>
+     *
+     * @param r The red component of the color to convert
+     * @param g The green component of the color to convert
+     * @param b The blue component of the color to convert
+     * @param a The alpha component of the color to convert, in \([0..1]\)
+     * @param source The source color space, cannot be null
+     * @param destination The destination color space, cannot be null
+     * @return A color long in the destination color space
+     *
+     * @see #convert(float, float, float, float, ColorSpace.Connector)
+     */
+    @ColorLong
+    public static long convert(float r, float g, float b, float a,
+            @NonNull ColorSpace source, @NonNull ColorSpace destination) {
+        float[] c = ColorSpace.connect(source, destination).transform(r, g, b);
+        return pack(c[0], c[1], c[2], a, destination);
+    }
+
+    /**
+     * <p>Converts the specified color long from a color space to another using the
+     * specified color space {@link ColorSpace.Connector connector}. The resulting
+     * color is returned as a color long. See the documentation of this class for a
+     * description of the color long format.</p>
+     *
+     * <p>When converting several colors in a row, this method is preferable to
+     * {@link #convert(long, ColorSpace)} as it prevents a new connector from being
+     * created on every invocation.</p>
+     *
+     * <p class="note">The connector's source color space should match the color long's
+     * color space.</p>
+     *
+     * @param color The color long to convert
+     * @param connector A color space connector, cannot be null
+     * @return A color long in the destination color space of the connector
+     */
+    @ColorLong
+    public static long convert(@ColorLong long color, @NonNull ColorSpace.Connector connector) {
+        float r = red(color);
+        float g = green(color);
+        float b = blue(color);
+        float a = alpha(color);
+        return convert(r, g, b, a, connector);
+    }
+
+    /**
+     * <p>Converts the specified 3 component color from a color space to another using
+     * the specified color space {@link ColorSpace.Connector connector}. The resulting
+     * color is returned as a color long. See the documentation of this class for a
+     * description of the color long format.</p>
+     *
+     * <p>When converting several colors in a row, this method is preferable to
+     * {@link #convert(float, float, float, float, ColorSpace, ColorSpace)} as
+     * it prevents a new connector from being created on every invocation.</p>
+     *
+     * <p>The red, green and blue components must be in the range defined by the
+     * source color space of the connector. See {@link ColorSpace#getMinValue(int)}
+     * and {@link ColorSpace#getMaxValue(int)}.</p>
+     *
+     * @param r The red component of the color to convert
+     * @param g The green component of the color to convert
+     * @param b The blue component of the color to convert
+     * @param a The alpha component of the color to convert, in \([0..1]\)
+     * @param connector A color space connector, cannot be null
+     * @return A color long in the destination color space of the connector
+     *
+     * @see #convert(float, float, float, float, ColorSpace, ColorSpace)
+     */
+    @ColorLong
+    public static long convert(float r, float g, float b, float a,
+            @NonNull ColorSpace.Connector connector) {
+        float[] c = connector.transform(r, g, b);
+        return pack(c[0], c[1], c[2], a, connector.getDestination());
+    }
+
+    /**
+     * <p>Returns the relative luminance of a color.</p>
+     *
+     * <p>Based on the formula for relative luminance defined in WCAG 2.0,
+     * W3C Recommendation 11 December 2008.</p>
+     *
+     * @return A value between 0 (darkest black) and 1 (lightest white)
+     *
+     * @throws IllegalArgumentException If the specified color's color space
+     * does not use the {@link ColorSpace.Model#RGB RGB} color model
+     */
+    public static float luminance(@ColorLong long color) {
+        ColorSpace colorSpace = colorSpace(color);
+        if (colorSpace.getModel() != ColorSpace.Model.RGB) {
+            throw new IllegalArgumentException("The specified color must be encoded in an RGB " +
+                    "color space. The supplied color space is " + colorSpace.getModel());
+        }
+
+        DoubleUnaryOperator eotf = ((ColorSpace.Rgb) colorSpace).getEotf();
+        double r = eotf.applyAsDouble(red(color));
+        double g = eotf.applyAsDouble(green(color));
+        double b = eotf.applyAsDouble(blue(color));
+
+        return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b)));
+    }
+
+    private static float saturate(float v) {
+        return v <= 0.0f ? 0.0f : (v >= 1.0f ? 1.0f : v);
+    }
+
     /**
      * Return the alpha component of a color int. This is the same as saying
      * color >>> 24
      */
+    @IntRange(from = 0, to = 255)
     public static int alpha(int color) {
         return color >>> 24;
     }
@@ -63,6 +1209,7 @@
      * Return the red component of a color int. This is the same as saying
      * (color >> 16) & 0xFF
      */
+    @IntRange(from = 0, to = 255)
     public static int red(int color) {
         return (color >> 16) & 0xFF;
     }
@@ -71,6 +1218,7 @@
      * Return the green component of a color int. This is the same as saying
      * (color >> 8) & 0xFF
      */
+    @IntRange(from = 0, to = 255)
     public static int green(int color) {
         return (color >> 8) & 0xFF;
     }
@@ -79,41 +1227,86 @@
      * Return the blue component of a color int. This is the same as saying
      * color & 0xFF
      */
+    @IntRange(from = 0, to = 255)
     public static int blue(int color) {
         return color & 0xFF;
     }
 
     /**
      * Return a color-int from red, green, blue components.
-     * The alpha component is implicity 255 (fully opaque).
-     * These component values should be [0..255], but there is no
+     * The alpha component is implicitly 255 (fully opaque).
+     * These component values should be \([0..255]\), but there is no
      * range check performed, so if they are out of range, the
      * returned color is undefined.
-     * @param red  Red component [0..255] of the color
-     * @param green Green component [0..255] of the color
-     * @param blue  Blue component [0..255] of the color
+     *
+     * @param red  Red component \([0..255]\) of the color
+     * @param green Green component \([0..255]\) of the color
+     * @param blue  Blue component \([0..255]\) of the color
      */
     @ColorInt
-    public static int rgb(int red, int green, int blue) {
+    public static int rgb(
+            @IntRange(from = 0, to = 255) int red,
+            @IntRange(from = 0, to = 255) int green,
+            @IntRange(from = 0, to = 255) int blue) {
         return 0xff000000 | (red << 16) | (green << 8) | blue;
     }
 
     /**
-     * Return a color-int from alpha, red, green, blue components.
-     * These component values should be [0..255], but there is no
-     * range check performed, so if they are out of range, the
+     * Return a color-int from red, green, blue float components
+     * in the range \([0..1]\). The alpha component is implicitly
+     * 1.0 (fully opaque). If the components are out of range, the
      * returned color is undefined.
-     * @param alpha Alpha component [0..255] of the color
-     * @param red   Red component [0..255] of the color
-     * @param green Green component [0..255] of the color
-     * @param blue  Blue component [0..255] of the color
+     *
+     * @param red Red component \([0..1]\) of the color
+     * @param green Green component \([0..1]\) of the color
+     * @param blue Blue component \([0..1]\) of the color
      */
     @ColorInt
-    public static int argb(int alpha, int red, int green, int blue) {
+    public static int rgb(float red, float green, float blue) {
+        return 0xff000000 |
+               ((int) (red   * 255.0f + 0.5f) << 16) |
+               ((int) (green * 255.0f + 0.5f) <<  8) |
+                (int) (blue  * 255.0f + 0.5f);
+    }
+
+    /**
+     * Return a color-int from alpha, red, green, blue components.
+     * These component values should be \([0..255]\), but there is no
+     * range check performed, so if they are out of range, the
+     * returned color is undefined.
+     * @param alpha Alpha component \([0..255]\) of the color
+     * @param red Red component \([0..255]\) of the color
+     * @param green Green component \([0..255]\) of the color
+     * @param blue Blue component \([0..255]\) of the color
+     */
+    @ColorInt
+    public static int argb(
+            @IntRange(from = 0, to = 255) int alpha,
+            @IntRange(from = 0, to = 255) int red,
+            @IntRange(from = 0, to = 255) int green,
+            @IntRange(from = 0, to = 255) int blue) {
         return (alpha << 24) | (red << 16) | (green << 8) | blue;
     }
 
     /**
+     * Return a color-int from alpha, red, green, blue float components
+     * in the range \([0..1]\). If the components are out of range, the
+     * returned color is undefined.
+     *
+     * @param alpha Alpha component \([0..1]\) of the color
+     * @param red Red component \([0..1]\) of the color
+     * @param green Green component \([0..1]\) of the color
+     * @param blue Blue component \([0..1]\) of the color
+     */
+    @ColorInt
+    public static int argb(float alpha, float red, float green, float blue) {
+        return ((int) (alpha * 255.0f + 0.5f) << 24) |
+               ((int) (red   * 255.0f + 0.5f) << 16) |
+               ((int) (green * 255.0f + 0.5f) <<  8) |
+                (int) (blue  * 255.0f + 0.5f);
+    }
+
+    /**
      * Returns the relative luminance of a color.
      * <p>
      * Assumes sRGB encoding. Based on the formula for relative luminance
@@ -124,23 +1317,31 @@
     public static float luminance(@ColorInt int color) {
         ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
         DoubleUnaryOperator eotf = cs.getEotf();
-        double red = eotf.applyAsDouble(Color.red(color) / 255.0);
-        double green = eotf.applyAsDouble(Color.green(color) / 255.0);
-        double blue = eotf.applyAsDouble(Color.blue(color) / 255.0);
-        return (float) ((0.2126 * red) + (0.7152 * green) + (0.0722 * blue));
+
+        double r = eotf.applyAsDouble(red(color) / 255.0);
+        double g = eotf.applyAsDouble(green(color) / 255.0);
+        double b = eotf.applyAsDouble(blue(color) / 255.0);
+
+        return (float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b));
     }
 
     /**
-     * Parse the color string, and return the corresponding color-int.
+     * </p>Parse the color string, and return the corresponding color-int.
      * If the string cannot be parsed, throws an IllegalArgumentException
-     * exception. Supported formats are:
-     * #RRGGBB
-     * #AARRGGBB
-     * or one of the following names:
-     * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
-     * 'yellow', 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey',
-     * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
-     * 'silver', 'teal'.
+     * exception. Supported formats are:</p>
+     *
+     * <ul>
+     *   <li><code>#RRGGBB</code></li>
+     *   <li><code>#AARRGGBB</code></li>
+     * </ul>
+     *
+     * <p>The following names are also accepted: <code>red</code>, <code>blue</code>,
+     * <code>green</code>, <code>black</code>, <code>white</code>, <code>gray</code>,
+     * <code>cyan</code>, <code>magenta</code>, <code>yellow</code>, <code>lightgray</code>,
+     * <code>darkgray</code>, <code>grey</code>, <code>lightgrey</code>, <code>darkgrey</code>,
+     * <code>aqua</code>, <code>fuchsia</code>, <code>lime</code>, <code>maroon</code>,
+     * <code>navy</code>, <code>olive</code>, <code>purple</code>, <code>silver</code>,
+     * and <code>teal</code>.</p>
      */
     @ColorInt
     public static int parseColor(@Size(min=1) String colorString) {
@@ -165,15 +1366,20 @@
 
     /**
      * Convert RGB components to HSV.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
-     * @param red  red component value [0..255]
-     * @param green  green component value [0..255]
-     * @param blue  blue component value [0..255]
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
+     * @param red  red component value \([0..255]\)
+     * @param green  green component value \([0..255]\)
+     * @param blue  blue component value \([0..255]\)
      * @param hsv  3 element array which holds the resulting HSV components.
      */
-    public static void RGBToHSV(int red, int green, int blue, @Size(3) float hsv[]) {
+    public static void RGBToHSV(
+            @IntRange(from = 0, to = 255) int red,
+            @IntRange(from = 0, to = 255) int green,
+            @IntRange(from = 0, to = 255) int blue, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -181,10 +1387,12 @@
     }
 
     /**
-     * Convert the argb color to its HSV components.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
+     * Convert the ARGB color to its HSV components.
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
      * @param color the argb color to convert. The alpha component is ignored.
      * @param hsv  3 element array which holds the resulting HSV components.
      */
@@ -194,13 +1402,16 @@
 
     /**
      * Convert HSV components to an ARGB color. Alpha set to 0xFF.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
      * If hsv values are out of range, they are pinned.
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
     */
+    @ColorInt
     public static int HSVToColor(@Size(3) float hsv[]) {
         return HSVToColor(0xFF, hsv);
     }
@@ -208,15 +1419,18 @@
     /**
      * Convert HSV components to an ARGB color. The alpha component is passed
      * through unchanged.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
      * If hsv values are out of range, they are pinned.
      * @param alpha the alpha component of the returned argb color.
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
-    */
-    public static int HSVToColor(int alpha, @Size(3) float hsv[]) {
+     */
+    @ColorInt
+    public static int HSVToColor(@IntRange(from = 0, to = 255) int alpha, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -236,7 +1450,7 @@
      * @hide
      */
     @ColorInt
-    public static int getHtmlColor(String color) {
+    public static int getHtmlColor(@NonNull String color) {
         Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
         if (i != null) {
             return i;
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index d968516..ec00c45 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.AnyThread;
 import android.annotation.ColorInt;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -126,7 +127,8 @@
  *
  * <p>To visualize and debug color spaces, you can call {@link #createRenderer()}.
  * The {@link Renderer} created by calling this method can be used to compare
- * color spaces and locate specific colors on a CIE 1931 chromaticity diagram.</p>
+ * color spaces and locate specific colors on a CIE 1931 or CIE 1976 UCS
+ * chromaticity diagram.</p>
  *
  * <p>The following code snippet shows how to render a bitmap that compares
  * the color gamuts and white points of {@link Named#DCI_P3} and
@@ -155,6 +157,7 @@
  * @see Adaptation
  * @see Renderer
  */
+@AnyThread
 @SuppressWarnings("StaticInitializerReferencesSubClass")
 public abstract class ColorSpace {
     /**
@@ -216,7 +219,7 @@
      *
      * @see #getId()
      */
-    public static final int MAX_ID = 64; // Do not change, used to encode in longs
+    public static final int MAX_ID = 63; // Do not change, used to encode in longs
 
     private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
     private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f };
@@ -341,11 +344,11 @@
          *             \end{equation}\)
          *         </td>
          *     </tr>
-         *     <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
+         *     <tr><td>Range</td><td colspan="4">\([-0.799..2.399[\)</td></tr>
          * </table>
          * <p>
          *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
-         *     <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+         *     <figcaption style="text-align: center;">Extended sRGB (orange) vs sRGB (white)</figcaption>
          * </p>
          */
         EXTENDED_SRGB,
@@ -368,11 +371,11 @@
          *         <td>Electro-optical transfer function</td>
          *         <td colspan="4">\(C_{linear} = C_{scRGB}\)</td>
          *     </tr>
-         *     <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
+         *     <tr><td>Range</td><td colspan="4">\([-0.5..7.499[\)</td></tr>
          * </table>
          * <p>
          *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
-         *     <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+         *     <figcaption style="text-align: center;">Extended sRGB (orange) vs sRGB (white)</figcaption>
          * </p>
          */
         LINEAR_EXTENDED_SRGB,
@@ -1090,7 +1093,7 @@
      * space's color model. The resulting value is passed back in the specified
      * array.</p>
      *
-     * <p class="note>The specified array's length  must be at least equal to
+     * <p class="note">The specified array's length  must be at least equal to
      * to the number of color components as returned by
      * {@link Model#getComponentCount()}, and its first 3 values must
      * be the XYZ components to convert from.</p>
@@ -1125,6 +1128,7 @@
      * @return A string representation of the object
      */
     @Override
+    @NonNull
     public String toString() {
         return mName + " (id=" + mId + ", model=" + mModel + ")";
     }
@@ -1403,7 +1407,7 @@
                 ILLUMINANT_D65,
                 x -> absRcpResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
                 x -> absResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
-                -0.5f, 7.5f,
+                -0.799f, 2.399f,
                 Named.EXTENDED_SRGB.ordinal()
         );
         sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
@@ -1412,7 +1416,7 @@
                 ILLUMINANT_D65,
                 DoubleUnaryOperator.identity(),
                 DoubleUnaryOperator.identity(),
-                -0.5f, 7.5f,
+                -0.5f, 7.499f,
                 Named.LINEAR_EXTENDED_SRGB.ordinal()
         );
         sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb(
@@ -1437,8 +1441,8 @@
                 "SMPTE RP 431-2-2007 DCI (P3)",
                 new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
                 new float[] { 0.314f, 0.351f },
-                x -> Math.pow(x, 1 / 2.6),
-                x -> Math.pow(x, 2.6),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 1 / 2.6),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 2.6),
                 0.0f, 1.0f,
                 Named.DCI_P3.ordinal()
         );
@@ -1473,8 +1477,8 @@
                 "Adobe RGB (1998)",
                 new float[] { 0.64f, 0.33f, 0.21f, 0.71f, 0.15f, 0.06f },
                 ILLUMINANT_D65,
-                x -> Math.pow(x, 1 / 2.2),
-                x -> Math.pow(x, 2.2),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 1 / 2.2),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 2.2),
                 0.0f, 1.0f,
                 Named.ADOBE_RGB.ordinal()
         );
@@ -1720,6 +1724,7 @@
     /**
      * Implementation of the CIE XYZ color space. Assumes the white point is D50.
      */
+    @AnyThread
     private static final class Xyz extends ColorSpace {
         private Xyz(@NonNull String name, @IntRange(from = MIN_ID, to = MAX_ID) int id) {
             super(name, Model.XYZ, id);
@@ -1765,6 +1770,7 @@
      * Implementation of the CIE L*a*b* color space. Its PCS is CIE XYZ
      * with a white point of D50.
      */
+    @AnyThread
     private static final class Lab extends ColorSpace {
         private static final float A = 216.0f / 24389.0f;
         private static final float B = 841.0f / 108.0f;
@@ -1949,6 +1955,7 @@
      * <p>To learn more about the white point adaptation process, refer to the
      * documentation of {@link Adaptation}.</p>
      */
+    @AnyThread
     public static class Rgb extends ColorSpace {
         @NonNull private final float[] mWhitePoint;
         @NonNull private final float[] mPrimaries;
@@ -2337,7 +2344,7 @@
          * to "gamma space" (gamma encoded). The terms gamma space and gamma encoded
          * are frequently used because many OETFs can be closely approximated using
          * a simple power function of the form \(x^{\frac{1}{\gamma}}\) (the
-         * approximation of the {@link Named#SRGB sRGB} EOTF uses \(\gamma=2.2\)
+         * approximation of the {@link Named#SRGB sRGB} OETF uses \(\gamma=2.2\)
          * for instance).</p>
          *
          * @return A transfer function that converts from linear space to "gamma space"
@@ -2346,7 +2353,7 @@
          */
         @NonNull
         public DoubleUnaryOperator getOetf() {
-            return mOetf;
+            return mClampedOetf;
         }
 
         /**
@@ -2369,7 +2376,7 @@
          */
         @NonNull
         public DoubleUnaryOperator getEotf() {
-            return mEotf;
+            return mClampedEotf;
         }
 
         @Override
@@ -2924,6 +2931,7 @@
      * @see ColorSpace#connect(ColorSpace, RenderIntent)
      * @see ColorSpace#connect(ColorSpace)
      */
+    @AnyThread
     public static class Connector {
         @NonNull private final ColorSpace mSource;
         @NonNull private final ColorSpace mDestination;
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 2733c43f..8673e0b 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -17,8 +17,8 @@
 package android.graphics;
 
 import android.content.res.AssetManager;
+import android.text.FontConfig;
 import android.util.Log;
-import dalvik.annotation.optimization.CriticalNative;
 
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -40,11 +40,11 @@
      */
     public long mNativePtr;
 
-    // Points native font family builder. Must be zero after freezing this family.
-    private long mBuilderPtr;
-
     public FontFamily() {
-        mBuilderPtr = nInitBuilder(null, 0);
+        mNativePtr = nCreateFamily(null, 0);
+        if (mNativePtr == 0) {
+            throw new IllegalStateException("error creating native FontFamily");
+        }
     }
 
     public FontFamily(String lang, String variant) {
@@ -54,15 +54,10 @@
         } else if ("elegant".equals(variant)) {
             varEnum = 2;
         }
-        mBuilderPtr = nInitBuilder(lang, varEnum);
-    }
-
-    public void freeze() {
-        if (mBuilderPtr == 0) {
-            throw new IllegalStateException("This FontFamily is already frozen");
+        mNativePtr = nCreateFamily(lang, varEnum);
+        if (mNativePtr == 0) {
+            throw new IllegalStateException("error creating native FontFamily");
         }
-        mNativePtr = nCreateFamily(mBuilderPtr);
-        mBuilderPtr = 0;
     }
 
     @Override
@@ -75,45 +70,33 @@
     }
 
     public boolean addFont(String path, int ttcIndex) {
-        if (mBuilderPtr == 0) {
-            throw new IllegalStateException("Unable to call addFont after freezing.");
-        }
         try (FileInputStream file = new FileInputStream(path)) {
             FileChannel fileChannel = file.getChannel();
             long fontSize = fileChannel.size();
             ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
-            return nAddFont(mBuilderPtr, fontBuffer, ttcIndex);
+            return nAddFont(mNativePtr, fontBuffer, ttcIndex);
         } catch (IOException e) {
             Log.e(TAG, "Error mapping font file " + path);
             return false;
         }
     }
 
-    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes,
+    public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontConfig.Axis> axes,
             int weight, boolean style) {
-        if (mBuilderPtr == 0) {
-            throw new IllegalStateException("Unable to call addFontWeightStyle after freezing.");
-        }
-        return nAddFontWeightStyle(mBuilderPtr, font, ttcIndex, axes, weight, style);
+        return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
     }
 
-    public boolean addFontFromAsset(AssetManager mgr, String path) {
-        if (mBuilderPtr == 0) {
-            throw new IllegalStateException("Unable to call addFontFromAsset after freezing.");
-        }
-        return nAddFontFromAsset(mBuilderPtr, mgr, path);
+    public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
+            boolean isAsset) {
+        return nAddFontFromAssetManager(mNativePtr, mgr, path, cookie, isAsset);
     }
 
-    private static native long nInitBuilder(String lang, int variant);
-
-    @CriticalNative
-    private static native long nCreateFamily(long mBuilderPtr);
-
-    @CriticalNative
+    private static native long nCreateFamily(String lang, int variant);
     private static native void nUnrefFamily(long nativePtr);
-    private static native boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex);
-    private static native boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
-            int ttcIndex, List<FontListParser.Axis> listOfAxis,
+    private static native boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex);
+    private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+            int ttcIndex, List<FontConfig.Axis> listOfAxis,
             int weight, boolean isItalic);
-    private static native boolean nAddFontFromAsset(long builderPtr, AssetManager mgr, String path);
+    private static native boolean nAddFontFromAssetManager(long nativeFamily, AssetManager mgr,
+            String path, int cookie, boolean isAsset);
 }
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 5b53296..4ec564a 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,12 +16,12 @@
 
 package android.graphics;
 
+import android.text.FontConfig;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.Nullable;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
@@ -37,61 +37,8 @@
  */
 public class FontListParser {
 
-    public static class Config {
-        Config() {
-            families = new ArrayList<Family>();
-            aliases = new ArrayList<Alias>();
-        }
-        public List<Family> families;
-        public List<Alias> aliases;
-    }
-
-    public static class Axis {
-        Axis(int tag, float styleValue) {
-            this.tag = tag;
-            this.styleValue = styleValue;
-        }
-        public final int tag;
-        public final float styleValue;
-    }
-
-    public static class Font {
-        Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
-            this.fontName = fontName;
-            this.ttcIndex = ttcIndex;
-            this.axes = axes;
-            this.weight = weight;
-            this.isItalic = isItalic;
-        }
-        public String fontName;
-        public int ttcIndex;
-        public final List<Axis> axes;
-        public int weight;
-        public boolean isItalic;
-    }
-
-    public static class Alias {
-        public String name;
-        public String toName;
-        public int weight;
-    }
-
-    public static class Family {
-        public Family(String name, List<Font> fonts, String lang, String variant) {
-            this.name = name;
-            this.fonts = fonts;
-            this.lang = lang;
-            this.variant = variant;
-        }
-
-        public String name;
-        public List<Font> fonts;
-        public String lang;
-        public String variant;
-    }
-
     /* Parse fallback list (no names) */
-    public static Config parse(InputStream in) throws XmlPullParserException, IOException {
+    public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
         try {
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(in, null);
@@ -105,12 +52,9 @@
     // Note that a well-formed variation contains a four-character tag and a float as styleValue,
     // with spacers in between. The tag is enclosd either by double quotes or single quotes.
     @VisibleForTesting
-    public static ArrayList<Axis> parseFontVariationSettings(@Nullable String settings) {
-        ArrayList<Axis> axisList = new ArrayList<>();
-        if (settings == null) {
-            return axisList;
-        }
+    public static FontConfig.Axis[] parseFontVariationSettings(String settings) {
         String[] settingList = settings.split(",");
+        ArrayList<FontConfig.Axis> axisList = new ArrayList<>();
         settingLoop:
         for (String setting : settingList) {
             int pos = 0;
@@ -152,9 +96,9 @@
             }
             int tag = makeTag(tagString.charAt(0), tagString.charAt(1), tagString.charAt(2),
                     tagString.charAt(3));
-            axisList.add(new Axis(tag, styleValue));
+            axisList.add(new FontConfig.Axis(tag, styleValue));
         }
-        return axisList;
+        return axisList.toArray(new FontConfig.Axis[axisList.size()]);
     }
 
     @VisibleForTesting
@@ -166,17 +110,17 @@
         return c == ' ' || c == '\r' || c == '\t' || c == '\n';
     }
 
-    private static Config readFamilies(XmlPullParser parser)
+    private static FontConfig readFamilies(XmlPullParser parser)
             throws XmlPullParserException, IOException {
-        Config config = new Config();
+        FontConfig config = new FontConfig();
         parser.require(XmlPullParser.START_TAG, null, "familyset");
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
             if (tag.equals("family")) {
-                config.families.add(readFamily(parser));
+                config.getFamilies().add(readFamily(parser));
             } else if (tag.equals("alias")) {
-                config.aliases.add(readAlias(parser));
+                config.getAliases().add(readAlias(parser));
             } else {
                 skip(parser);
             }
@@ -184,12 +128,12 @@
         return config;
     }
 
-    private static Family readFamily(XmlPullParser parser)
+    private static FontConfig.Family readFamily(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         String name = parser.getAttributeValue(null, "name");
         String lang = parser.getAttributeValue(null, "lang");
         String variant = parser.getAttributeValue(null, "variant");
-        List<Font> fonts = new ArrayList<Font>();
+        List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
         while (parser.next() != XmlPullParser.END_TAG) {
             if (parser.getEventType() != XmlPullParser.START_TAG) continue;
             String tag = parser.getName();
@@ -199,18 +143,18 @@
                 skip(parser);
             }
         }
-        return new Family(name, fonts, lang, variant);
+        return new FontConfig.Family(name, fonts, lang, variant);
     }
 
     /** Matches leading and trailing XML whitespace. */
     private static final Pattern FILENAME_WHITESPACE_PATTERN =
             Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
 
-    private static Font readFont(XmlPullParser parser)
+    private static FontConfig.Font readFont(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         String indexStr = parser.getAttributeValue(null, "index");
         int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
-        List<Axis> axes = new ArrayList<Axis>();
+        List<FontConfig.Axis> axes = new ArrayList<FontConfig.Axis>();
         String weightStr = parser.getAttributeValue(null, "weight");
         int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
         boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
@@ -229,7 +173,7 @@
         }
         String fullFilename = "/system/fonts/" +
                 FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
-        return new Font(fullFilename, index, axes, weight, isItalic);
+        return new FontConfig.Font(fullFilename, index, axes, weight, isItalic);
     }
 
     /** The 'tag' attribute value is read as four character values between U+0020 and U+007E
@@ -243,7 +187,7 @@
     private static final Pattern STYLE_VALUE_PATTERN =
             Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
 
-    private static Axis readAxis(XmlPullParser parser)
+    private static FontConfig.Axis readAxis(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         int tag = 0;
         String tagStr = parser.getAttributeValue(null, "tag");
@@ -262,22 +206,22 @@
         }
 
         skip(parser);  // axis tag is empty, ignore any contents and consume end tag
-        return new Axis(tag, styleValue);
+        return new FontConfig.Axis(tag, styleValue);
     }
 
-    private static Alias readAlias(XmlPullParser parser)
+    private static FontConfig.Alias readAlias(XmlPullParser parser)
             throws XmlPullParserException, IOException {
-        Alias alias = new Alias();
-        alias.name = parser.getAttributeValue(null, "name");
-        alias.toName = parser.getAttributeValue(null, "to");
+        String name = parser.getAttributeValue(null, "name");
+        String toName = parser.getAttributeValue(null, "to");
         String weightStr = parser.getAttributeValue(null, "weight");
+        int weight;
         if (weightStr == null) {
-            alias.weight = 400;
+            weight = 400;
         } else {
-            alias.weight = Integer.parseInt(weightStr);
+            weight = Integer.parseInt(weightStr);
         }
         skip(parser);  // alias tag is empty, ignore any contents and consume end tag
-        return alias;
+        return new FontConfig.Alias(name, toName, weight);
     }
 
     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 4ee0c34..7815ae1 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -71,7 +71,6 @@
 
     private LocaleList  mLocales;
     private String      mFontFeatureSettings;
-    private String      mFontVariationSettings;
 
     private static final Object sCacheLock = new Object();
 
@@ -1495,37 +1494,6 @@
     }
 
     /**
-     * Returns the font variation settings.
-     *
-     * @return the paint's currently set font variation settings. Default is null.
-     *
-     * @see #setFontVariationSettings(String)
-     */
-    public String getFontVariationSettings() {
-        return mFontVariationSettings;
-    }
-
-    /**
-     * Set font variation settings.
-     *
-     * @param settings font variation settings, e.g. "'wdth' 300, 'wght' 1.8"
-     *
-     * @see #getFontVariationSettings()
-     *
-     * @param settings the font variation settings. You can pass null or empty string as no
-     *                 variation settings.
-     */
-    public void setFontVariationSettings(String settings) {
-        settings = TextUtils.nullIfEmpty(settings);
-        if (settings == mFontVariationSettings
-                || (settings != null && settings.equals(mFontVariationSettings))) {
-            return;
-        }
-        mFontVariationSettings = settings;
-        setTypeface(Typeface.createFromTypefaceWithVariation(mTypeface, settings));
-    }
-
-    /**
      * Get the current value of hyphen edit.
      *
      * @return the current hyphen edit value
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 166ef1b..0a349e9 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -16,12 +16,13 @@
 
 package android.graphics;
 
+import android.annotation.NonNull;
 import android.content.res.AssetManager;
+import android.text.FontConfig;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.LruCache;
 import android.util.SparseArray;
-import android.graphics.FontListParser;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -110,6 +111,30 @@
     }
 
     /**
+     * @hide
+     * Used by Resources.
+     */
+    @NonNull
+    public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
+        if (sFallbackFonts != null) {
+            synchronized (sDynamicTypefaceCache) {
+                final String key = createAssetUid(mgr, path);
+                Typeface typeface = sDynamicTypefaceCache.get(key);
+                if (typeface != null) return typeface;
+
+                FontFamily fontFamily = new FontFamily();
+                if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */)) {
+                    FontFamily[] families = { fontFamily };
+                    typeface = createFromFamiliesWithDefault(families);
+                    sDynamicTypefaceCache.put(key, typeface);
+                    return typeface;
+                }
+            }
+        }
+        throw new RuntimeException("Font resource not found " + path);
+    }
+
+    /**
      * Create a typeface object given a family name, and option style information.
      * If null is passed for the name, then the "default" font will be chosen.
      * The resulting typeface object can be queried (getStyle()) to discover what
@@ -172,15 +197,6 @@
         return typeface;
     }
 
-    /** @hide */
-    public static Typeface createFromTypefaceWithVariation(Typeface family,
-            String fontVariationSettings) {
-        final long ni = family == null ? 0 : family.native_instance;
-        ArrayList<FontListParser.Axis> axes =
-                FontListParser.parseFontVariationSettings(fontVariationSettings);
-        return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes));
-    }
-
     /**
      * Returns one of the default typeface objects, based on the specified style
      *
@@ -205,8 +221,7 @@
                 if (typeface != null) return typeface;
 
                 FontFamily fontFamily = new FontFamily();
-                if (fontFamily.addFontFromAsset(mgr, path)) {
-                    fontFamily.freeze();
+                if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */)) {
                     FontFamily[] families = { fontFamily };
                     typeface = createFromFamiliesWithDefault(families);
                     sDynamicTypefaceCache.put(key, typeface);
@@ -256,7 +271,6 @@
         if (sFallbackFonts != null) {
             FontFamily fontFamily = new FontFamily();
             if (fontFamily.addFont(path, 0 /* ttcIndex */)) {
-                fontFamily.freeze();
                 FontFamily[] families = { fontFamily };
                 return createFromFamiliesWithDefault(families);
             }
@@ -306,28 +320,27 @@
         mStyle = nativeGetStyle(ni);
     }
 
-    private static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+    private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
             Map<String, ByteBuffer> bufferForPath) {
-        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
-        for (FontListParser.Font font : family.fonts) {
-            ByteBuffer fontBuffer = bufferForPath.get(font.fontName);
+        FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
+        for (FontConfig.Font font : family.getFonts()) {
+            ByteBuffer fontBuffer = bufferForPath.get(font.getFontName());
             if (fontBuffer == null) {
-                try (FileInputStream file = new FileInputStream(font.fontName)) {
+                try (FileInputStream file = new FileInputStream(font.getFontName())) {
                     FileChannel fileChannel = file.getChannel();
                     long fontSize = fileChannel.size();
                     fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
-                    bufferForPath.put(font.fontName, fontBuffer);
+                    bufferForPath.put(font.getFontName(), fontBuffer);
                 } catch (IOException e) {
-                    Log.e(TAG, "Error mapping font file " + font.fontName);
+                    Log.e(TAG, "Error mapping font file " + font.getFontName());
                     continue;
                 }
             }
-            if (!fontFamily.addFontWeightStyle(fontBuffer, font.ttcIndex, font.axes,
-                    font.weight, font.isItalic)) {
-                Log.e(TAG, "Error creating font " + font.fontName + "#" + font.ttcIndex);
+            if (!fontFamily.addFontWeightStyle(fontBuffer, font.getTtcIndex(), font.getAxes(),
+                    font.getWeight(), font.isItalic())) {
+                Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
             }
         }
-        fontFamily.freeze();
         return fontFamily;
     }
 
@@ -342,16 +355,16 @@
         File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
         try {
             FileInputStream fontsIn = new FileInputStream(configFilename);
-            FontListParser.Config fontConfig = FontListParser.parse(fontsIn);
+            FontConfig fontConfig = FontListParser.parse(fontsIn);
 
             Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();
 
             List<FontFamily> familyList = new ArrayList<FontFamily>();
             // Note that the default typeface is always present in the fallback list;
             // this is an enhancement from pre-Minikin behavior.
-            for (int i = 0; i < fontConfig.families.size(); i++) {
-                FontListParser.Family f = fontConfig.families.get(i);
-                if (i == 0 || f.name == null) {
+            for (int i = 0; i < fontConfig.getFamilies().size(); i++) {
+                FontConfig.Family f = fontConfig.getFamilies().get(i);
+                if (i == 0 || f.getName() == null) {
                     familyList.add(makeFamilyFromParsed(f, bufferForPath));
                 }
             }
@@ -359,10 +372,10 @@
             setDefault(Typeface.createFromFamilies(sFallbackFonts));
 
             Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
-            for (int i = 0; i < fontConfig.families.size(); i++) {
+            for (int i = 0; i < fontConfig.getFamilies().size(); i++) {
                 Typeface typeface;
-                FontListParser.Family f = fontConfig.families.get(i);
-                if (f.name != null) {
+                FontConfig.Family f = fontConfig.getFamilies().get(i);
+                if (f.getName() != null) {
                     if (i == 0) {
                         // The first entry is the default typeface; no sense in
                         // duplicating the corresponding FontFamily.
@@ -372,17 +385,17 @@
                         FontFamily[] families = { fontFamily };
                         typeface = Typeface.createFromFamiliesWithDefault(families);
                     }
-                    systemFonts.put(f.name, typeface);
+                    systemFonts.put(f.getName(), typeface);
                 }
             }
-            for (FontListParser.Alias alias : fontConfig.aliases) {
-                Typeface base = systemFonts.get(alias.toName);
+            for (FontConfig.Alias alias : fontConfig.getAliases()) {
+                Typeface base = systemFonts.get(alias.getToName());
                 Typeface newFace = base;
-                int weight = alias.weight;
+                int weight = alias.getWeight();
                 if (weight != 400) {
                     newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
                 }
-                systemFonts.put(alias.name, newFace);
+                systemFonts.put(alias.getName(), newFace);
             }
             sSystemFontMap = systemFonts;
 
@@ -453,8 +466,6 @@
     }
 
     private static native long nativeCreateFromTypeface(long native_instance, int style);
-    private static native long nativeCreateFromTypefaceWithVariation(
-            long native_instance, List<FontListParser.Axis> axes);
     private static native long nativeCreateWeightAlias(long native_instance, int weight);
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
diff --git a/graphics/tests/graphicstests/Android.mk b/graphics/tests/graphicstests/Android.mk
index 1845395..8ea44bd 100644
--- a/graphics/tests/graphicstests/Android.mk
+++ b/graphics/tests/graphicstests/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := FrameworksGraphicsTests
 
 include $(BUILD_PACKAGE)
diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
index 23de416..2b4e6c2 100644
--- a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
+++ b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
@@ -17,101 +17,103 @@
 package android.graphics;
 
 import android.test.suitebuilder.annotation.SmallTest;
-import java.util.List;
+import android.text.FontConfig;
 import junit.framework.TestCase;
 
+import java.util.List;
+
 
 public class VariationParserTest extends TestCase {
 
     @SmallTest
     public void testParseFontVariationSetting() {
         int tag = FontListParser.makeTag('w', 'd', 't', 'h');
-        List<FontListParser.Axis> axes = FontListParser.parseFontVariationSettings("'wdth' 1");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(1.0f, axes.get(0).styleValue);
+        FontConfig.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("\"wdth\" 100");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(100.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("\"wdth\" 100");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(100.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("   'wdth' 100");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(100.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("   'wdth' 100");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(100.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(0.5f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(0.5f, axis[0].getStyleValue());
 
         tag = FontListParser.makeTag('A', 'X', ' ', ' ');
-        axes = FontListParser.parseFontVariationSettings("'AX  ' 1");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(1.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("'AX  ' 1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("'AX  '\t1");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(1.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("'AX  '\t1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("'AX  '\n1");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(1.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("'AX  '\n1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("'AX  '\r1");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(1.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("'AX  '\r1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
-        axes = FontListParser.parseFontVariationSettings("'AX  '\r\t\n 1");
-        assertEquals(tag, axes.get(0).tag);
-        assertEquals(1.0f, axes.get(0).styleValue);
+        axis = FontListParser.parseFontVariationSettings("'AX  '\r\t\n 1");
+        assertEquals(tag, axis[0].getTag());
+        assertEquals(1.0f, axis[0].getStyleValue());
 
         // Test for invalid input
-        axes = FontListParser.parseFontVariationSettings("");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("invalid_form");
-        assertEquals(0, axes.size());
+        axis = FontListParser.parseFontVariationSettings("");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("invalid_form");
+        assertEquals(0, axis.length);
 
         // Test with invalid tag
-        axes = FontListParser.parseFontVariationSettings("'' 1");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'invalid' 1");
-        assertEquals(0, axes.size());
+        axis = FontListParser.parseFontVariationSettings("'' 1");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'invalid' 1");
+        assertEquals(0, axis.length);
 
         // Test with invalid styleValue
-        axes = FontListParser.parseFontVariationSettings("'wdth' ");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'wdth' x");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'wdth' \t");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'wdth' \n\r");
-        assertEquals(0, axes.size());
+        axis = FontListParser.parseFontVariationSettings("'wdth' ");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'wdth' x");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'wdth' \t");
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'wdth' \n\r");
+        assertEquals(0, axis.length);
     }
 
     @SmallTest
     public void testParseFontVariationStyleSettings() {
-        List<FontListParser.Axis> axes =
+        FontConfig.Axis[] axis =
                 FontListParser.parseFontVariationSettings("'wdth' 10,'AX  '\r1");
         int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
         int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
-        assertEquals(tag1, axes.get(0).tag);
-        assertEquals(10.0f, axes.get(0).styleValue);
-        assertEquals(tag2, axes.get(1).tag);
-        assertEquals(1.0f, axes.get(1).styleValue);
+        assertEquals(tag1, axis[0].getTag());
+        assertEquals(10.0f, axis[0].getStyleValue());
+        assertEquals(tag2, axis[1].getTag());
+        assertEquals(1.0f, axis[1].getStyleValue());
 
         // Test only spacers are allowed before tag
-        axes = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
+        axis = FontListParser.parseFontVariationSettings("     'wdth' 10,ab'wdth' 1");
         tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
-        assertEquals(tag1, axes.get(0).tag);
-        assertEquals(10.0f, axes.get(0).styleValue);
-        assertEquals(1, axes.size());
+        assertEquals(tag1, axis[0].getTag());
+        assertEquals(10.0f, axis[0].getStyleValue());
+        assertEquals(1, axis.length);
     }
 
     @SmallTest
     public void testInvalidTagCharacters() {
-        List<FontListParser.Axis> axes =
+        FontConfig.Axis[] axis =
                 FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10");
-        assertEquals(0, axes.size());
-        axes = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
-        assertEquals(0, axes.size());
+        assertEquals(0, axis.length);
+        axis = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10");
+        assertEquals(0, axis.length);
     }
 
     @SmallTest
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index d6b1cf1..bf7a779a 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -45,6 +45,7 @@
                 PURPOSE_DECRYPT,
                 PURPOSE_SIGN,
                 PURPOSE_VERIFY,
+                PURPOSE_WRAP_KEY,
                 })
     public @interface PurposeEnum {}
 
@@ -69,6 +70,12 @@
     public static final int PURPOSE_VERIFY = 1 << 3;
 
     /**
+     * Purpose of key: wrapping key for secure key import.
+     */
+    public static final int PURPOSE_WRAP_KEY = 1 << 4;
+
+
+    /**
      * @hide
      */
     public static abstract class Purpose {
@@ -84,6 +91,8 @@
                     return KeymasterDefs.KM_PURPOSE_SIGN;
                 case PURPOSE_VERIFY:
                     return KeymasterDefs.KM_PURPOSE_VERIFY;
+                case PURPOSE_WRAP_KEY:
+                    return KeymasterDefs.KM_PURPOSE_WRAP_KEY;
                 default:
                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
             }
@@ -99,6 +108,8 @@
                     return PURPOSE_SIGN;
                 case KeymasterDefs.KM_PURPOSE_VERIFY:
                     return PURPOSE_VERIFY;
+                case KeymasterDefs.KM_PURPOSE_WRAP_KEY:
+                    return PURPOSE_WRAP_KEY;
                 default:
                     throw new IllegalArgumentException("Unknown purpose: " + purpose);
             }
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
index 35388d7..a740b13 100644
--- a/keystore/tests/Android.mk
+++ b/keystore/tests/Android.mk
@@ -6,6 +6,7 @@
 LOCAL_CERTIFICATE := platform
 
 LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 5e72a0d..0a814f3 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -18,7 +18,8 @@
 
 # Build the legacy-test library
 # =============================
-# This contains the junit.framework classes that were in Android API level 25.
+# This contains the junit.framework and android.test classes that were in
+# Android API level 25.
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -28,6 +29,18 @@
 
 include $(BUILD_JAVA_LIBRARY)
 
+# Build the legacy-android-test library
+# =============================
+# This contains the android.test classes that were in Android API level 25.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/android)
+LOCAL_MODULE := legacy-android-test
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
 ifeq ($(HOST_OS),linux)
 # Build the legacy-performance-test-hostdex library
 # =================================================
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index d501d25..fb89835 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -24,10 +24,14 @@
         "-Wunreachable-code",
     ],
     srcs: [
+        "ApkAssets.cpp",
         "Asset.cpp",
         "AssetDir.cpp",
         "AssetManager.cpp",
+        "AssetManager2.cpp",
         "AttributeResolution.cpp",
+        "ChunkIterator.cpp",
+        "LoadedArsc.cpp",
         "LocaleData.cpp",
         "misc.cpp",
         "ObbFile.cpp",
@@ -65,7 +69,16 @@
             shared: {
                 enabled: false,
             },
-            shared_libs: ["libz-host"],
+            static_libs: [
+                "libziparchive",
+                "libbase",
+                "liblog",
+                "libcutils",
+                "libutils",
+            ],
+            shared_libs: [
+                "libz-host",
+            ],
         },
         windows: {
             enabled: true,
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
new file mode 100644
index 0000000..55f4c3c
--- /dev/null
+++ b/libs/androidfw/ApkAssets.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/ApkAssets.h"
+
+#include "android-base/logging.h"
+#include "utils/Trace.h"
+#include "ziparchive/zip_archive.h"
+
+#include "androidfw/Asset.h"
+#include "androidfw/Util.h"
+
+namespace android {
+
+std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path) {
+  ATRACE_NAME("ApkAssets::Load");
+  ::ZipArchiveHandle unmanaged_handle;
+  int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+  if (result != 0) {
+    LOG(ERROR) << ::ErrorCodeString(result);
+    return {};
+  }
+
+  // Wrap the handle in a unique_ptr so it gets automatically closed.
+  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets());
+  loaded_apk->zip_handle_.reset(unmanaged_handle);
+
+  ::ZipString entry_name("resources.arsc");
+  ::ZipEntry entry;
+  result = ::FindEntry(loaded_apk->zip_handle_.get(), entry_name, &entry);
+  if (result != 0) {
+    LOG(ERROR) << ::ErrorCodeString(result);
+    return {};
+  }
+
+  if (entry.method == kCompressDeflated) {
+    LOG(WARNING) << "resources.arsc is compressed.";
+  }
+
+  loaded_apk->resources_asset_ =
+      loaded_apk->Open("resources.arsc", Asset::AccessMode::ACCESS_BUFFER);
+  if (loaded_apk->resources_asset_ == nullptr) {
+    return {};
+  }
+
+  loaded_apk->path_ = path;
+  loaded_apk->loaded_arsc_ =
+      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
+                       loaded_apk->resources_asset_->getLength());
+  if (loaded_apk->loaded_arsc_ == nullptr) {
+    return {};
+  }
+  return loaded_apk;
+}
+
+std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode /*mode*/) const {
+  ATRACE_NAME("ApkAssets::Open");
+  CHECK(zip_handle_ != nullptr);
+
+  ::ZipString name(path.c_str());
+  ::ZipEntry entry;
+  int32_t result = ::FindEntry(zip_handle_.get(), name, &entry);
+  if (result != 0) {
+    LOG(ERROR) << "No entry '" << path << "' found in APK.";
+    return {};
+  }
+
+  if (entry.method == kCompressDeflated) {
+    auto compressed_asset = util::make_unique<_CompressedAsset>();
+    if (compressed_asset->openChunk(::GetFileDescriptor(zip_handle_.get()), entry.offset,
+                                    entry.method, entry.uncompressed_length,
+                                    entry.compressed_length) != NO_ERROR) {
+      LOG(ERROR) << "Failed to decompress '" << path << "'.";
+      return {};
+    }
+    return std::move(compressed_asset);
+  } else {
+    auto uncompressed_asset = util::make_unique<_FileAsset>();
+    if (uncompressed_asset->openChunk(path.c_str(), ::GetFileDescriptor(zip_handle_.get()),
+                                      entry.offset, entry.uncompressed_length) != NO_ERROR) {
+      LOG(ERROR) << "Failed to mmap '" << path << "'.";
+      return {};
+    }
+    return std::move(uncompressed_asset);
+  }
+  return {};
+}
+
+}  // namespace android
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
new file mode 100644
index 0000000..8d65925
--- /dev/null
+++ b/libs/androidfw/AssetManager2.cpp
@@ -0,0 +1,576 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/AssetManager2.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "utils/ByteOrder.h"
+#include "utils/Trace.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+namespace android {
+
+AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
+
+bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
+                                 bool invalidate_caches) {
+  apk_assets_ = apk_assets;
+  if (invalidate_caches) {
+    InvalidateCaches(static_cast<uint32_t>(-1));
+  }
+  return true;
+}
+
+const std::vector<const ApkAssets*> AssetManager2::GetApkAssets() const { return apk_assets_; }
+
+const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const {
+  if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
+    return nullptr;
+  }
+  return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
+}
+
+void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
+  const int diff = configuration_.diff(configuration);
+  configuration_ = configuration;
+
+  if (diff) {
+    InvalidateCaches(static_cast<uint32_t>(diff));
+  }
+}
+
+const ResTable_config& AssetManager2::GetConfiguration() const { return configuration_; }
+
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
+  const std::string new_path = "assets/" + filename;
+  return OpenNonAsset(new_path, mode);
+}
+
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
+                                           Asset::AccessMode mode) {
+  const std::string new_path = "assets/" + filename;
+  return OpenNonAsset(new_path, cookie, mode);
+}
+
+// Search in reverse because that's how we used to do it and we need to preserve behaviour.
+// This is unfortunate, because ClassLoaders delegate to the parent first, so the order
+// is inconsistent for split APKs.
+std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
+                                                   Asset::AccessMode mode,
+                                                   ApkAssetsCookie* out_cookie) {
+  ATRACE_CALL();
+  for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
+    std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
+    if (asset) {
+      if (out_cookie != nullptr) {
+        *out_cookie = i;
+      }
+      return asset;
+    }
+  }
+
+  if (out_cookie != nullptr) {
+    *out_cookie = kInvalidCookie;
+  }
+  return {};
+}
+
+std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
+                                                   ApkAssetsCookie cookie, Asset::AccessMode mode) {
+  ATRACE_CALL();
+  if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
+    return {};
+  }
+  return apk_assets_[cookie]->Open(filename, mode);
+}
+
+ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
+                                         bool stop_at_first_match, LoadedArsc::Entry* out_entry,
+                                         ResTable_config* out_selected_config,
+                                         uint32_t* out_flags) {
+  ATRACE_CALL();
+
+  // Might use this if density_override != 0.
+  ResTable_config density_override_config;
+
+  // Select our configuration or generate a density override configuration.
+  ResTable_config* desired_config = &configuration_;
+  if (density_override != 0 && density_override != configuration_.density) {
+    density_override_config = configuration_;
+    density_override_config.density = density_override;
+    desired_config = &density_override_config;
+  }
+
+  LoadedArsc::Entry best_entry;
+  ResTable_config best_config;
+  int32_t best_index = -1;
+  uint32_t cumulated_flags = 0;
+
+  const size_t apk_asset_count = apk_assets_.size();
+  for (size_t i = 0; i < apk_asset_count; i++) {
+    const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();
+
+    LoadedArsc::Entry current_entry;
+    ResTable_config current_config;
+    uint32_t flags = 0;
+    if (!loaded_arsc->FindEntry(resid, *desired_config, &current_entry, &current_config, &flags)) {
+      continue;
+    }
+
+    cumulated_flags |= flags;
+
+    if (best_index == -1 || current_config.isBetterThan(best_config, desired_config)) {
+      best_entry = current_entry;
+      best_config = current_config;
+      best_index = static_cast<int32_t>(i);
+      if (stop_at_first_match) {
+        break;
+      }
+    }
+  }
+
+  if (best_index == -1) {
+    return kInvalidCookie;
+  }
+
+  *out_entry = best_entry;
+  *out_selected_config = best_config;
+  *out_flags = cumulated_flags;
+  return best_index;
+}
+
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
+  ATRACE_CALL();
+
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  uint32_t flags = 0u;
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     true /* stop_at_first_match */, &entry, &config, &flags);
+  if (cookie == kInvalidCookie) {
+    return false;
+  }
+
+  const std::string* package_name =
+      apk_assets_[cookie]->GetLoadedArsc()->GetPackageNameForId(resid);
+  if (package_name == nullptr) {
+    return false;
+  }
+
+  out_name->package = package_name->data();
+  out_name->package_len = package_name->size();
+
+  out_name->type = entry.type_string_ref.string8(&out_name->type_len);
+  out_name->type16 = nullptr;
+  if (out_name->type == nullptr) {
+    out_name->type16 = entry.type_string_ref.string16(&out_name->type_len);
+    if (out_name->type16 == nullptr) {
+      return false;
+    }
+  }
+
+  out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len);
+  out_name->entry16 = nullptr;
+  if (out_name->entry == nullptr) {
+    out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len);
+    if (out_name->entry16 == nullptr) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     false /* stop_at_first_match */, &entry, &config, out_flags);
+  return cookie != kInvalidCookie;
+}
+
+ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
+                                           uint16_t density_override, Res_value* out_value,
+                                           ResTable_config* out_selected_config,
+                                           uint32_t* out_flags) {
+  ATRACE_CALL();
+
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  uint32_t flags = 0u;
+  ApkAssetsCookie cookie =
+      FindEntry(resid, density_override, false /* stop_at_first_match */, &entry, &config, &flags);
+  if (cookie == kInvalidCookie) {
+    return kInvalidCookie;
+  }
+
+  if (dtohl(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
+    if (!may_be_bag) {
+      LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
+    }
+    return kInvalidCookie;
+  }
+
+  const Res_value* device_value = reinterpret_cast<const Res_value*>(
+      reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
+  out_value->copyFrom_dtoh(*device_value);
+  *out_selected_config = config;
+  *out_flags = flags;
+  return cookie;
+}
+
+const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
+  ATRACE_CALL();
+
+  auto cached_iter = cached_bags_.find(resid);
+  if (cached_iter != cached_bags_.end()) {
+    return cached_iter->second.get();
+  }
+
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  uint32_t flags = 0u;
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     false /* stop_at_first_match */, &entry, &config, &flags);
+  if (cookie == kInvalidCookie) {
+    return nullptr;
+  }
+
+  // Check that the size of the entry header is at least as big as
+  // the desired ResTable_map_entry. Also verify that the entry
+  // was intended to be a map.
+  if (dtohs(entry.entry->size) < sizeof(ResTable_map_entry) ||
+      (dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) == 0) {
+    // Not a bag, nothing to do.
+    return nullptr;
+  }
+
+  const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry.entry);
+  const ResTable_map* map_entry =
+      reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size);
+  const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
+
+  const uint32_t parent = dtohl(map->parent.ident);
+  if (parent == 0) {
+    // There is no parent, meaning there is nothing to inherit and we can do a simple
+    // copy of the entries in the map.
+    const size_t entry_count = map_entry_end - map_entry;
+    util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
+        malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
+    ResolvedBag::Entry* new_entry = new_bag->entries;
+    for (; map_entry != map_entry_end; ++map_entry) {
+      new_entry->cookie = cookie;
+      new_entry->value.copyFrom_dtoh(map_entry->value);
+      new_entry->key = dtohl(map_entry->name.ident);
+      new_entry->key_pool = nullptr;
+      new_entry->type_pool = nullptr;
+      ++new_entry;
+    }
+    new_bag->type_spec_flags = flags;
+    new_bag->entry_count = static_cast<uint32_t>(entry_count);
+    ResolvedBag* result = new_bag.get();
+    cached_bags_[resid] = std::move(new_bag);
+    return result;
+  }
+
+  // Get the parent and do a merge of the keys.
+  const ResolvedBag* parent_bag = GetBag(parent);
+  if (parent_bag == nullptr) {
+    // Failed to get the parent that should exist.
+    return nullptr;
+  }
+
+  // Combine flags from the parent and our own bag.
+  flags |= parent_bag->type_spec_flags;
+
+  // Create the max possible entries we can make. Once we construct the bag,
+  // we will realloc to fit to size.
+  const size_t max_count = parent_bag->entry_count + dtohl(map->count);
+  ResolvedBag* new_bag = reinterpret_cast<ResolvedBag*>(
+      malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))));
+  ResolvedBag::Entry* new_entry = new_bag->entries;
+
+  const ResolvedBag::Entry* parent_entry = parent_bag->entries;
+  const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count;
+
+  // The keys are expected to be in sorted order. Merge the two bags.
+  while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
+    const uint32_t child_key = dtohl(map_entry->name.ident);
+    if (child_key <= parent_entry->key) {
+      // Use the child key if it comes before the parent
+      // or is equal to the parent (overrides).
+      new_entry->cookie = cookie;
+      new_entry->value.copyFrom_dtoh(map_entry->value);
+      new_entry->key = child_key;
+      new_entry->key_pool = nullptr;
+      new_entry->type_pool = nullptr;
+      ++map_entry;
+    } else {
+      // Take the parent entry as-is.
+      memcpy(new_entry, parent_entry, sizeof(*new_entry));
+    }
+
+    if (child_key >= parent_entry->key) {
+      // Move to the next parent entry if we used it or it was overridden.
+      ++parent_entry;
+    }
+    // Increment to the next entry to fill.
+    ++new_entry;
+  }
+
+  // Finish the child entries if they exist.
+  while (map_entry != map_entry_end) {
+    new_entry->cookie = cookie;
+    new_entry->value.copyFrom_dtoh(map_entry->value);
+    new_entry->key = dtohl(map_entry->name.ident);
+    new_entry->key_pool = nullptr;
+    new_entry->type_pool = nullptr;
+    ++map_entry;
+    ++new_entry;
+  }
+
+  // Finish the parent entries if they exist.
+  if (parent_entry != parent_entry_end) {
+    // Take the rest of the parent entries as-is.
+    const size_t num_entries_to_copy = parent_entry_end - parent_entry;
+    memcpy(new_entry, parent_entry, num_entries_to_copy * sizeof(*new_entry));
+    new_entry += num_entries_to_copy;
+  }
+
+  // Resize the resulting array to fit.
+  const size_t actual_count = new_entry - new_bag->entries;
+  if (actual_count != max_count) {
+    new_bag = reinterpret_cast<ResolvedBag*>(
+        realloc(new_bag, sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))));
+  }
+
+  util::unique_cptr<ResolvedBag> final_bag{new_bag};
+  final_bag->type_spec_flags = flags;
+  final_bag->entry_count = static_cast<uint32_t>(actual_count);
+  ResolvedBag* result = final_bag.get();
+  cached_bags_[resid] = std::move(final_bag);
+  return result;
+}
+
+void AssetManager2::InvalidateCaches(uint32_t diff) {
+  if (diff == 0xffffffffu) {
+    // Everything must go.
+    cached_bags_.clear();
+    return;
+  }
+
+  // Be more conservative with what gets purged. Only if the bag has other possible
+  // variations with respect to what changed (diff) should we remove it.
+  for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) {
+    if (diff & iter->second->type_spec_flags) {
+      iter = cached_bags_.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+}
+
+std::unique_ptr<Theme> AssetManager2::NewTheme() { return std::unique_ptr<Theme>(new Theme(this)); }
+
+bool Theme::ApplyStyle(uint32_t resid, bool force) {
+  ATRACE_CALL();
+
+  const ResolvedBag* bag = asset_manager_->GetBag(resid);
+  if (bag == nullptr) {
+    return false;
+  }
+
+  // Merge the flags from this style.
+  type_spec_flags_ |= bag->type_spec_flags;
+
+  // On the first iteration, verify the attribute IDs and
+  // update the entry count in each type.
+  const auto bag_iter_end = end(bag);
+  for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
+    const uint32_t attr_resid = bag_iter->key;
+
+    // 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)) {
+      return false;
+    }
+
+    const uint32_t package_idx = util::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);
+
+    std::unique_ptr<Package>& package = packages_[package_idx];
+    if (package == nullptr) {
+      package.reset(new Package());
+    }
+
+    util::unique_cptr<Type>& type = package->types[type_idx];
+    if (type == nullptr) {
+      // Set the initial capacity to take up a total amount of 1024 bytes.
+      constexpr uint32_t kInitialCapacity = (1024u - sizeof(Type)) / sizeof(Entry);
+      const uint32_t initial_capacity = std::max(entry_idx, kInitialCapacity);
+      type.reset(
+          reinterpret_cast<Type*>(calloc(sizeof(Type) + (initial_capacity * sizeof(Entry)), 1)));
+      type->entry_capacity = initial_capacity;
+    }
+
+    // Set the entry_count to include this entry. We will populate
+    // and resize the array as necessary in the next pass.
+    if (entry_idx + 1 > type->entry_count) {
+      // Increase the entry count to include this.
+      type->entry_count = entry_idx + 1;
+    }
+  }
+
+  // On the second pass, we will realloc to fit the entry counts
+  // 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);
+    Package* package = packages_[package_idx].get();
+    util::unique_cptr<Type>& type = package->types[type_idx];
+    if (type->entry_count != type->entry_capacity) {
+      // Resize to fit the actual entries that will be included.
+      Type* type_ptr = type.release();
+      type.reset(reinterpret_cast<Type*>(
+          realloc(type_ptr, sizeof(Type) + (type_ptr->entry_count * sizeof(Entry)))));
+      if (type->entry_capacity < type->entry_count) {
+        // Clear the newly allocated memory (which does not get zero initialized).
+        // We need to do this because we |= type_spec_flags.
+        memset(type->entries + type->entry_capacity, 0,
+               sizeof(Entry) * (type->entry_count - type->entry_capacity));
+      }
+      type->entry_capacity = type->entry_count;
+    }
+    Entry& entry = type->entries[entry_idx];
+    if (force || entry.value.dataType == Res_value::TYPE_NULL) {
+      entry.cookie = bag_iter->cookie;
+      entry.type_spec_flags |= bag->type_spec_flags;
+      entry.value = bag_iter->value;
+    }
+  }
+  return true;
+}
+
+ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
+                                    uint32_t* out_flags) const {
+  constexpr const int kMaxIterations = 20;
+
+  uint32_t type_spec_flags = 0u;
+
+  for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) {
+    if (!util::is_valid_resid(resid)) {
+      return kInvalidCookie;
+    }
+
+    const uint32_t package_idx = util::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 Package* package = packages_[package_idx].get();
+    if (package == nullptr) {
+      return kInvalidCookie;
+    }
+
+    const Type* type = package->types[type_idx].get();
+    if (type == nullptr) {
+      return kInvalidCookie;
+    }
+
+    if (entry_idx >= type->entry_count) {
+      return kInvalidCookie;
+    }
+
+    const Entry& entry = type->entries[entry_idx];
+    type_spec_flags |= entry.type_spec_flags;
+
+    switch (entry.value.dataType) {
+      case Res_value::TYPE_ATTRIBUTE:
+        resid = entry.value.data;
+        break;
+
+      case Res_value::TYPE_NULL:
+        return kInvalidCookie;
+
+      default:
+        *out_value = entry.value;
+        if (out_flags != nullptr) {
+          *out_flags = type_spec_flags;
+        }
+        return entry.cookie;
+    }
+  }
+
+  LOG(WARNING) << base::StringPrintf("Too many (%d) attribute references, stopped at: 0x%08x",
+                                     kMaxIterations, resid);
+  return kInvalidCookie;
+}
+
+void Theme::Clear() {
+  type_spec_flags_ = 0u;
+  for (std::unique_ptr<Package>& package : packages_) {
+    package.reset();
+  }
+}
+
+bool Theme::SetTo(const Theme& o) {
+  if (this == &o) {
+    return true;
+  }
+
+  if (asset_manager_ != o.asset_manager_) {
+    return false;
+  }
+
+  type_spec_flags_ = o.type_spec_flags_;
+
+  for (size_t p = 0; p < arraysize(packages_); p++) {
+    const Package* package = o.packages_[p].get();
+    if (package == nullptr) {
+      packages_[p].reset();
+      continue;
+    }
+
+    for (size_t t = 0; t < arraysize(package->types); t++) {
+      const Type* type = package->types[t].get();
+      if (type == nullptr) {
+        packages_[p]->types[t].reset();
+        continue;
+      }
+
+      const size_t type_alloc_size = sizeof(Type) + (type->entry_capacity * sizeof(Entry));
+      void* copied_data = malloc(type_alloc_size);
+      memcpy(copied_data, type, type_alloc_size);
+      packages_[p]->types[t].reset(reinterpret_cast<Type*>(copied_data));
+    }
+  }
+  return true;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/Chunk.h b/libs/androidfw/Chunk.h
new file mode 100644
index 0000000..e87b940
--- /dev/null
+++ b/libs/androidfw/Chunk.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef CHUNK_H_
+#define CHUNK_H_
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "utils/ByteOrder.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+#include "androidfw/ResourceTypes.h"
+
+namespace android {
+
+// Helpful wrapper around a ResChunk_header that provides getter methods
+// that handle endianness conversions and provide access to the data portion
+// of the chunk.
+class Chunk {
+ public:
+  explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {}
+
+  // Returns the type of the chunk. Caller need not worry about endianness.
+  inline int type() const { return dtohs(device_chunk_->type); }
+
+  // Returns the size of the entire chunk. This can be useful for skipping
+  // over the entire chunk. Caller need not worry about endianness.
+  inline size_t size() const { return dtohl(device_chunk_->size); }
+
+  // Returns the size of the header. Caller need not worry about endianness.
+  inline size_t header_size() const { return dtohs(device_chunk_->headerSize); }
+
+  template <typename T>
+  inline const T* header() const {
+    if (header_size() >= sizeof(T)) {
+      return reinterpret_cast<const T*>(device_chunk_);
+    }
+    return nullptr;
+  }
+
+  inline const void* data_ptr() const {
+    return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size();
+  }
+
+  inline size_t data_size() const { return size() - header_size(); }
+
+ private:
+  const ResChunk_header* device_chunk_;
+};
+
+// Provides a Java style iterator over an array of ResChunk_header's.
+// Validation is performed while iterating.
+// The caller should check if there was an error during chunk validation
+// by calling HadError() and GetLastError() to get the reason for failure.
+// Example:
+//
+//   ChunkIterator iter(data_ptr, data_len);
+//   while (iter.HasNext()) {
+//     const Chunk chunk = iter.Next();
+//     ...
+//   }
+//
+//   if (iter.HadError()) {
+//     LOG(ERROR) << iter.GetLastError();
+//   }
+//
+class ChunkIterator {
+ public:
+  ChunkIterator(const void* data, size_t len)
+      : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)),
+        len_(len),
+        last_error_(nullptr) {
+    CHECK(next_chunk_ != nullptr) << "data can't be nullptr";
+    VerifyNextChunk();
+  }
+
+  Chunk Next();
+  inline bool HasNext() const { return !HadError() && len_ != 0; };
+  inline bool HadError() const { return last_error_ != nullptr; }
+  inline std::string GetLastError() const { return last_error_; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ChunkIterator);
+
+  // Returns false if there was an error.
+  bool VerifyNextChunk();
+
+  const ResChunk_header* next_chunk_;
+  size_t len_;
+  const char* last_error_;
+};
+
+}  // namespace android
+
+#endif /* CHUNK_H_ */
diff --git a/libs/androidfw/ChunkIterator.cpp b/libs/androidfw/ChunkIterator.cpp
new file mode 100644
index 0000000..747aa4a
--- /dev/null
+++ b/libs/androidfw/ChunkIterator.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#include "Chunk.h"
+
+#include "android-base/logging.h"
+
+namespace android {
+
+Chunk ChunkIterator::Next() {
+  CHECK(len_ != 0) << "called Next() after last chunk";
+
+  const ResChunk_header* this_chunk = next_chunk_;
+
+  // We've already checked the values of this_chunk, so safely increment.
+  next_chunk_ = reinterpret_cast<const ResChunk_header*>(
+      reinterpret_cast<const uint8_t*>(this_chunk) + dtohl(this_chunk->size));
+  len_ -= dtohl(this_chunk->size);
+
+  if (len_ != 0) {
+    // Prepare the next chunk.
+    VerifyNextChunk();
+  }
+  return Chunk(this_chunk);
+}
+
+// Returns false if there was an error.
+bool ChunkIterator::VerifyNextChunk() {
+  const uintptr_t header_start = reinterpret_cast<uintptr_t>(next_chunk_);
+
+  // This data must be 4-byte aligned, since we directly
+  // access 32-bit words, which must be aligned on
+  // certain architectures.
+  if (header_start & 0x03) {
+    last_error_ = "header not aligned on 4-byte boundary";
+    return false;
+  }
+
+  if (len_ < sizeof(ResChunk_header)) {
+    last_error_ = "not enough space for header";
+    return false;
+  }
+
+  const size_t header_size = dtohs(next_chunk_->headerSize);
+  const size_t size = dtohl(next_chunk_->size);
+  if (header_size < sizeof(ResChunk_header)) {
+    last_error_ = "header size too small";
+    return false;
+  }
+
+  if (header_size > size) {
+    last_error_ = "header size is larger than entire chunk";
+    return false;
+  }
+
+  if (size > len_) {
+    last_error_ = "chunk size is bigger than given data";
+    return false;
+  }
+
+  if ((size | header_size) & 0x03) {
+    last_error_ = "header sizes are not aligned on 4-byte boundary";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
new file mode 100644
index 0000000..94d0d46
--- /dev/null
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/LoadedArsc.h"
+
+#include <cstddef>
+#include <limits>
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "utils/ByteOrder.h"
+#include "utils/Trace.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+#include "Chunk.h"
+#include "androidfw/ByteBucketArray.h"
+#include "androidfw/Util.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+
+namespace {
+
+// Element of a TypeSpec array. See TypeSpec.
+struct Type {
+  // The configuration for which this type defines entries.
+  // This is already converted to host endianness.
+  ResTable_config configuration;
+
+  // Pointer to the mmapped data where entry definitions are kept.
+  const ResTable_type* type;
+};
+
+// TypeSpec is going to be immediately proceeded by
+// an array of Type structs, all in the same block of memory.
+struct TypeSpec {
+  // Pointer to the mmapped data where flags are kept.
+  // Flags denote whether the resource entry is public
+  // and under which configurations it varies.
+  const ResTable_typeSpec* type_spec;
+
+  // The number of types that follow this struct.
+  // There is a type for each configuration
+  // that entries are defined for.
+  size_t type_count;
+
+  // Trick to easily access a variable number of Type structs
+  // proceeding this struct, and to ensure their alignment.
+  const Type types[0];
+};
+
+// TypeSpecPtr points to the block of memory that holds
+// a TypeSpec struct, followed by an array of Type structs.
+// TypeSpecPtr is a managed pointer that knows how to delete
+// itself.
+using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+
+// Builder that helps accumulate Type structs and then create a single
+// contiguous block of memory to store both the TypeSpec struct and
+// the Type structs.
+class TypeSpecPtrBuilder {
+ public:
+  TypeSpecPtrBuilder(const ResTable_typeSpec* header) : header_(header) {}
+
+  void AddType(const ResTable_type* type) {
+    ResTable_config config;
+    config.copyFromDtoH(type->config);
+    types_.push_back(Type{config, type});
+  }
+
+  TypeSpecPtr Build() {
+    // Check for overflow.
+    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) {
+      return {};
+    }
+    TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
+    type_spec->type_spec = header_;
+    type_spec->type_count = types_.size();
+    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
+    return TypeSpecPtr(type_spec);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);
+
+  const ResTable_typeSpec* header_;
+  std::vector<Type> types_;
+};
+
+}  // namespace
+
+class LoadedPackage {
+ public:
+  LoadedPackage() = default;
+
+  bool FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable_config& config,
+                 LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+                 uint32_t* out_flags) const;
+
+  ResStringPool type_string_pool_;
+  ResStringPool key_string_pool_;
+  std::string package_name_;
+  int package_id_ = -1;
+
+  ByteBucketArray<TypeSpecPtr> type_specs_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
+};
+
+bool LoadedPackage::FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable_config& config,
+                              LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+                              uint32_t* out_flags) const {
+  ATRACE_NAME("LoadedPackage::FindEntry");
+  const TypeSpecPtr& ptr = type_specs_[type_id];
+  if (ptr == nullptr) {
+    return false;
+  }
+
+  // Don't bother checking if the entry ID is larger than
+  // the number of entries.
+  if (entry_id >= dtohl(ptr->type_spec->entryCount)) {
+    return false;
+  }
+
+  const ResTable_config* best_config = nullptr;
+  const ResTable_type* best_type = nullptr;
+  uint32_t best_offset = 0;
+
+  for (uint32_t i = 0; i < ptr->type_count; i++) {
+    const Type* type = &ptr->types[i];
+
+    if (type->configuration.match(config) &&
+        (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
+      // The configuration matches and is better than the previous selection.
+      // Find the entry value if it exists for this configuration.
+      size_t entry_count = dtohl(type->type->entryCount);
+      if (entry_id < entry_count) {
+        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_id]);
+        if (offset != ResTable_type::NO_ENTRY) {
+          // There is an entry for this resource, record it.
+          best_config = &type->configuration;
+          best_type = type->type;
+          best_offset = offset + dtohl(type->type->entriesStart);
+        }
+      }
+    }
+  }
+
+  if (best_type == nullptr) {
+    return false;
+  }
+
+  const uint32_t* flags = reinterpret_cast<const uint32_t*>(ptr->type_spec + 1);
+  *out_flags = dtohl(flags[entry_id]);
+  *out_selected_config = *best_config;
+
+  const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
+      reinterpret_cast<const uint8_t*>(best_type) + best_offset);
+  out_entry->entry = best_entry;
+  out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
+  out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
+  return true;
+}
+
+// The destructor gets generated into arbitrary translation units
+// if left implicit, which causes the compiler to complain about
+// forward declarations and incomplete types.
+LoadedArsc::~LoadedArsc() {}
+
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry,
+                           ResTable_config* out_selected_config, uint32_t* out_flags) const {
+  ATRACE_NAME("LoadedArsc::FindEntry");
+  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);
+
+  if (type_id == 0) {
+    LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << ".";
+    return false;
+  }
+
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->package_id_ == package_id) {
+      return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry,
+                                       out_selected_config, out_flags);
+    }
+  }
+  return false;
+}
+
+const std::string* LoadedArsc::GetPackageNameForId(uint32_t resid) const {
+  const uint8_t package_id = util::get_package_id(resid);
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->package_id_ == package_id) {
+      return &loaded_package->package_name_;
+    }
+  }
+  return nullptr;
+}
+
+static bool VerifyType(const Chunk& chunk) {
+  ATRACE_CALL();
+  const ResTable_type* header = chunk.header<ResTable_type>();
+
+  const size_t entry_count = dtohl(header->entryCount);
+  if (entry_count > std::numeric_limits<uint16_t>::max()) {
+    LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_TYPE.";
+    return false;
+  }
+
+  // Make sure that there is enough room for the entry offsets.
+  const size_t offsets_offset = chunk.header_size();
+  const size_t entries_offset = dtohl(header->entriesStart);
+  const size_t offsets_length = sizeof(uint32_t) * entry_count;
+
+  if (offsets_offset + offsets_length > entries_offset) {
+    LOG(ERROR) << "Entry offsets overlap actual entry data.";
+    return false;
+  }
+
+  if (entries_offset > chunk.size()) {
+    LOG(ERROR) << "Entry offsets extend beyond chunk.";
+    return false;
+  }
+
+  if (entries_offset & 0x03) {
+    LOG(ERROR) << "Entries start at unaligned address.";
+    return false;
+  }
+
+  // Check each entry offset.
+  const uint32_t* offsets =
+      reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset);
+  for (size_t i = 0; i < entry_count; i++) {
+    uint32_t offset = dtohl(offsets[i]);
+    if (offset != ResTable_type::NO_ENTRY) {
+      // Check that the offset is aligned.
+      if (offset & 0x03) {
+        LOG(ERROR) << "Entry offset at index " << i << " is not 4-byte aligned.";
+        return false;
+      }
+
+      // Check that the offset doesn't overflow.
+      if (offset > std::numeric_limits<uint32_t>::max() - entries_offset) {
+        // Overflow in offset.
+        LOG(ERROR) << "Entry offset at index " << i << " is too large.";
+        return false;
+      }
+
+      offset += entries_offset;
+      if (offset > chunk.size() - sizeof(ResTable_entry)) {
+        LOG(ERROR) << "Entry offset at index " << i << " is too large. No room for ResTable_entry.";
+        return false;
+      }
+
+      const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
+          reinterpret_cast<const uint8_t*>(header) + offset);
+      const size_t entry_size = dtohs(entry->size);
+      if (entry_size < sizeof(*entry)) {
+        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too small.";
+        return false;
+      }
+
+      // Check the declared entrySize.
+      if (entry_size > chunk.size() || offset > chunk.size() - entry_size) {
+        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too large.";
+        return false;
+      }
+
+      // If this is a map entry, then keep validating.
+      if (entry_size >= sizeof(ResTable_map_entry)) {
+        const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry);
+        const size_t map_entry_count = dtohl(map->count);
+
+        size_t map_entries_start = offset + entry_size;
+        if (map_entries_start & 0x03) {
+          LOG(ERROR) << "Map entries start at unaligned offset.";
+          return false;
+        }
+
+        // Each entry is sizeof(ResTable_map) big.
+        if (map_entry_count > ((chunk.size() - map_entries_start) / sizeof(ResTable_map))) {
+          LOG(ERROR) << "Too many map entries in ResTable_map_entry.";
+          return false;
+        }
+
+        // Great, all the map entries fit!.
+      } else {
+        // There needs to be room for one Res_value struct.
+        if (offset + entry_size > chunk.size() - sizeof(Res_value)) {
+          LOG(ERROR) << "No room for Res_value after ResTable_entry.";
+          return false;
+        }
+
+        const Res_value* value = reinterpret_cast<const Res_value*>(
+            reinterpret_cast<const uint8_t*>(entry) + entry_size);
+        const size_t value_size = dtohs(value->size);
+        if (value_size < sizeof(Res_value)) {
+          LOG(ERROR) << "Res_value is too small.";
+          return false;
+        }
+
+        if (value_size > chunk.size() || offset + entry_size > chunk.size() - value_size) {
+          LOG(ERROR) << "Res_value size is too large.";
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
+  ATRACE_CALL();
+  const ResTable_package* header = chunk.header<ResTable_package>();
+  if (header == nullptr) {
+    LOG(ERROR) << "Chunk RES_TABLE_PACKAGE_TYPE is too small.";
+    return false;
+  }
+
+  loaded_package->package_id_ = dtohl(header->id);
+
+  // A TypeSpec builder. We use this to accumulate the set of Types
+  // available for a TypeSpec, and later build a single, contiguous block
+  // of memory that holds all the Types together with the TypeSpec.
+  std::unique_ptr<TypeSpecPtrBuilder> types_builder;
+
+  // Keep track of the last seen type index. Since type IDs are 1-based,
+  // this records their index, which is 0-based (type ID - 1).
+  uint8_t last_type_idx = 0;
+
+  ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
+  while (iter.HasNext()) {
+    const Chunk child_chunk = iter.Next();
+    switch (child_chunk.type()) {
+      case RES_STRING_POOL_TYPE: {
+        const uintptr_t pool_address =
+            reinterpret_cast<uintptr_t>(child_chunk.header<ResChunk_header>());
+        const uintptr_t header_address = reinterpret_cast<uintptr_t>(header);
+        if (pool_address == header_address + dtohl(header->typeStrings)) {
+          // This string pool is the type string pool.
+          status_t err = loaded_package->type_string_pool_.setTo(
+              child_chunk.header<ResStringPool_header>(), child_chunk.size());
+          if (err != NO_ERROR) {
+            LOG(ERROR) << "Corrupt package type string pool.";
+            return false;
+          }
+        } else if (pool_address == header_address + dtohl(header->keyStrings)) {
+          // This string pool is the key string pool.
+          status_t err = loaded_package->key_string_pool_.setTo(
+              child_chunk.header<ResStringPool_header>(), child_chunk.size());
+          if (err != NO_ERROR) {
+            LOG(ERROR) << "Corrupt package key string pool.";
+            return false;
+          }
+        } else {
+          LOG(WARNING) << "Too many string pool chunks found in package.";
+        }
+      } break;
+
+      case RES_TABLE_TYPE_SPEC_TYPE: {
+        ATRACE_NAME("LoadTableTypeSpec");
+
+        // Starting a new TypeSpec, so finish the old one if there was one.
+        if (types_builder) {
+          TypeSpecPtr type_spec_ptr = types_builder->Build();
+          if (type_spec_ptr == nullptr) {
+            LOG(ERROR) << "Too many type configurations, overflow detected.";
+            return false;
+          }
+
+          loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+
+          types_builder = {};
+          last_type_idx = 0;
+        }
+
+        const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
+        if (type_spec == nullptr) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE is too small.";
+          return false;
+        }
+
+        if (type_spec->id == 0) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0.";
+          return false;
+        }
+
+        // The data portion of this chunk contains entry_count 32bit entries,
+        // each one representing a set of flags.
+        // Here we only validate that the chunk is well formed.
+        const size_t entry_count = dtohl(type_spec->entryCount);
+
+        // There can only be 2^16 entries in a type, because that is the ID
+        // space for entries (EEEE) in the resource ID 0xPPTTEEEE.
+        if (entry_count > std::numeric_limits<uint16_t>::max()) {
+          LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_SPEC_TYPE: " << entry_count << ".";
+          return false;
+        }
+
+        if (entry_count * sizeof(uint32_t) > chunk.data_size()) {
+          LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_TYPE_SPEC_TYPE.";
+          return false;
+        }
+
+        last_type_idx = type_spec->id - 1;
+        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec);
+      } break;
+
+      case RES_TABLE_TYPE_TYPE: {
+        const ResTable_type* type = child_chunk.header<ResTable_type>();
+        if (type == nullptr) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE is too small.";
+          return false;
+        }
+
+        if (type->id == 0) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE has invalid ID 0.";
+          return false;
+        }
+
+        // Type chunks must be preceded by their TypeSpec chunks.
+        if (!types_builder || type->id - 1 != last_type_idx) {
+          LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without "
+                        "RES_TABLE_TYPE_SPEC_TYPE.";
+          return false;
+        }
+
+        if (!VerifyType(child_chunk)) {
+          return false;
+        }
+
+        types_builder->AddType(type);
+      } break;
+
+      default:
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        break;
+    }
+  }
+
+  // Finish the last TypeSpec.
+  if (types_builder) {
+    TypeSpecPtr type_spec_ptr = types_builder->Build();
+    if (type_spec_ptr == nullptr) {
+      LOG(ERROR) << "Too many type configurations, overflow detected.";
+      return false;
+    }
+    loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+  }
+
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return false;
+  }
+  return true;
+}
+
+bool LoadedArsc::LoadTable(const Chunk& chunk) {
+  ATRACE_CALL();
+  const ResTable_header* header = chunk.header<ResTable_header>();
+  if (header == nullptr) {
+    LOG(ERROR) << "Chunk RES_TABLE_TYPE is too small.";
+    return false;
+  }
+
+  const size_t package_count = dtohl(header->packageCount);
+  size_t packages_seen = 0;
+
+  packages_.reserve(package_count);
+
+  ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
+  while (iter.HasNext()) {
+    const Chunk child_chunk = iter.Next();
+    switch (child_chunk.type()) {
+      case RES_STRING_POOL_TYPE:
+        // Only use the first string pool. Ignore others.
+        if (global_string_pool_.getError() == NO_INIT) {
+          status_t err = global_string_pool_.setTo(child_chunk.header<ResStringPool_header>(),
+                                                   child_chunk.size());
+          if (err != NO_ERROR) {
+            LOG(ERROR) << "Corrupt string pool.";
+            return false;
+          }
+        } else {
+          LOG(WARNING) << "Multiple string pool chunks found in resource table.";
+        }
+        break;
+
+      case RES_TABLE_PACKAGE_TYPE: {
+        if (packages_seen + 1 > package_count) {
+          LOG(ERROR) << "More package chunks were found than the " << package_count
+                     << " declared in the "
+                        "header.";
+          return false;
+        }
+        packages_seen++;
+
+        std::unique_ptr<LoadedPackage> loaded_package = util::make_unique<LoadedPackage>();
+        if (!LoadPackage(child_chunk, loaded_package.get())) {
+          return false;
+        }
+        packages_.push_back(std::move(loaded_package));
+      } break;
+
+      default:
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        break;
+    }
+  }
+
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return false;
+  }
+  return true;
+}
+
+std::unique_ptr<LoadedArsc> LoadedArsc::Load(const void* data, size_t len) {
+  ATRACE_CALL();
+
+  // Not using make_unique because the constructor is private.
+  std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
+
+  ChunkIterator iter(data, len);
+  while (iter.HasNext()) {
+    const Chunk chunk = iter.Next();
+    switch (chunk.type()) {
+      case RES_TABLE_TYPE:
+        if (!loaded_arsc->LoadTable(chunk)) {
+          return {};
+        }
+        break;
+
+      default:
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        break;
+    }
+  }
+
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return {};
+  }
+  return loaded_arsc;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 1ac5085..7c381ef 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -1,4 +1,4 @@
-// Auto-generated by frameworks/base/tools/localedata/extract_icu_data.py
+// Auto-generated by ./tools/localedata/extract_icu_data.py
 
 const char SCRIPT_CODES[][4] = {
     /* 0  */ {'A', 'h', 'o', 'm'},
@@ -39,27 +39,27 @@
     /* 35 */ {'K', 'h', 'm', 'r'},
     /* 36 */ {'K', 'n', 'd', 'a'},
     /* 37 */ {'K', 'o', 'r', 'e'},
-    /* 38 */ {'K', 't', 'h', 'i'},
-    /* 39 */ {'L', 'a', 'n', 'a'},
-    /* 40 */ {'L', 'a', 'o', 'o'},
-    /* 41 */ {'L', 'a', 't', 'n'},
-    /* 42 */ {'L', 'e', 'p', 'c'},
-    /* 43 */ {'L', 'i', 'n', 'a'},
-    /* 44 */ {'L', 'i', 's', 'u'},
-    /* 45 */ {'L', 'y', 'c', 'i'},
-    /* 46 */ {'L', 'y', 'd', 'i'},
-    /* 47 */ {'M', 'a', 'n', 'd'},
-    /* 48 */ {'M', 'a', 'n', 'i'},
-    /* 49 */ {'M', 'e', 'r', 'c'},
-    /* 50 */ {'M', 'l', 'y', 'm'},
-    /* 51 */ {'M', 'o', 'n', 'g'},
-    /* 52 */ {'M', 'r', 'o', 'o'},
-    /* 53 */ {'M', 'y', 'm', 'r'},
-    /* 54 */ {'N', 'a', 'r', 'b'},
-    /* 55 */ {'N', 'k', 'o', 'o'},
-    /* 56 */ {'O', 'g', 'a', 'm'},
-    /* 57 */ {'O', 'r', 'k', 'h'},
-    /* 58 */ {'O', 'r', 'y', 'a'},
+    /* 38 */ {'L', 'a', 'n', 'a'},
+    /* 39 */ {'L', 'a', 'o', 'o'},
+    /* 40 */ {'L', 'a', 't', 'n'},
+    /* 41 */ {'L', 'e', 'p', 'c'},
+    /* 42 */ {'L', 'i', 'n', 'a'},
+    /* 43 */ {'L', 'i', 's', 'u'},
+    /* 44 */ {'L', 'y', 'c', 'i'},
+    /* 45 */ {'L', 'y', 'd', 'i'},
+    /* 46 */ {'M', 'a', 'n', 'd'},
+    /* 47 */ {'M', 'a', 'n', 'i'},
+    /* 48 */ {'M', 'e', 'r', 'c'},
+    /* 49 */ {'M', 'l', 'y', 'm'},
+    /* 50 */ {'M', 'o', 'n', 'g'},
+    /* 51 */ {'M', 'r', 'o', 'o'},
+    /* 52 */ {'M', 'y', 'm', 'r'},
+    /* 53 */ {'N', 'a', 'r', 'b'},
+    /* 54 */ {'N', 'k', 'o', 'o'},
+    /* 55 */ {'O', 'g', 'a', 'm'},
+    /* 56 */ {'O', 'r', 'k', 'h'},
+    /* 57 */ {'O', 'r', 'y', 'a'},
+    /* 58 */ {'O', 's', 'g', 'e'},
     /* 59 */ {'P', 'a', 'u', 'c'},
     /* 60 */ {'P', 'h', 'l', 'i'},
     /* 61 */ {'P', 'h', 'n', 'x'},
@@ -76,78 +76,147 @@
     /* 72 */ {'T', 'a', 'l', 'e'},
     /* 73 */ {'T', 'a', 'l', 'u'},
     /* 74 */ {'T', 'a', 'm', 'l'},
-    /* 75 */ {'T', 'a', 'v', 't'},
-    /* 76 */ {'T', 'e', 'l', 'u'},
-    /* 77 */ {'T', 'f', 'n', 'g'},
-    /* 78 */ {'T', 'h', 'a', 'a'},
-    /* 79 */ {'T', 'h', 'a', 'i'},
-    /* 80 */ {'T', 'i', 'b', 't'},
-    /* 81 */ {'U', 'g', 'a', 'r'},
-    /* 82 */ {'V', 'a', 'i', 'i'},
-    /* 83 */ {'X', 'p', 'e', 'o'},
-    /* 84 */ {'X', 's', 'u', 'x'},
-    /* 85 */ {'Y', 'i', 'i', 'i'},
-    /* 86 */ {'~', '~', '~', 'A'},
-    /* 87 */ {'~', '~', '~', 'B'},
+    /* 75 */ {'T', 'a', 'n', 'g'},
+    /* 76 */ {'T', 'a', 'v', 't'},
+    /* 77 */ {'T', 'e', 'l', 'u'},
+    /* 78 */ {'T', 'f', 'n', 'g'},
+    /* 79 */ {'T', 'h', 'a', 'a'},
+    /* 80 */ {'T', 'h', 'a', 'i'},
+    /* 81 */ {'T', 'i', 'b', 't'},
+    /* 82 */ {'U', 'g', 'a', 'r'},
+    /* 83 */ {'V', 'a', 'i', 'i'},
+    /* 84 */ {'X', 'p', 'e', 'o'},
+    /* 85 */ {'X', 's', 'u', 'x'},
+    /* 86 */ {'Y', 'i', 'i', 'i'},
+    /* 87 */ {'~', '~', '~', 'A'},
+    /* 88 */ {'~', '~', '~', 'B'},
 };
 
 
 const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
-    {0x61610000u, 41u}, // aa -> Latn
+    {0x61610000u, 40u}, // aa -> Latn
+    {0xA0000000u, 40u}, // aai -> Latn
+    {0xA8000000u, 40u}, // aak -> Latn
+    {0xD0000000u, 40u}, // aau -> Latn
     {0x61620000u, 15u}, // ab -> Cyrl
-    {0xC4200000u, 41u}, // abr -> Latn
-    {0x90400000u, 41u}, // ace -> Latn
-    {0x9C400000u, 41u}, // ach -> Latn
-    {0x80600000u, 41u}, // ada -> Latn
+    {0xA0200000u, 40u}, // abi -> Latn
+    {0xC4200000u, 40u}, // abr -> Latn
+    {0xCC200000u, 40u}, // abt -> Latn
+    {0xE0200000u, 40u}, // aby -> Latn
+    {0x8C400000u, 40u}, // acd -> Latn
+    {0x90400000u, 40u}, // ace -> Latn
+    {0x9C400000u, 40u}, // ach -> Latn
+    {0x80600000u, 40u}, // ada -> Latn
+    {0x90600000u, 40u}, // ade -> Latn
+    {0xA4600000u, 40u}, // adj -> Latn
     {0xE0600000u, 15u}, // ady -> Cyrl
+    {0xE4600000u, 40u}, // adz -> Latn
     {0x61650000u,  4u}, // ae -> Avst
     {0x84800000u,  1u}, // aeb -> Arab
-    {0x61660000u, 41u}, // af -> Latn
-    {0xC0C00000u, 41u}, // agq -> Latn
+    {0xE0800000u, 40u}, // aey -> Latn
+    {0x61660000u, 40u}, // af -> Latn
+    {0x88C00000u, 40u}, // agc -> Latn
+    {0x8CC00000u, 40u}, // agd -> Latn
+    {0x98C00000u, 40u}, // agg -> Latn
+    {0xB0C00000u, 40u}, // agm -> Latn
+    {0xB8C00000u, 40u}, // ago -> Latn
+    {0xC0C00000u, 40u}, // agq -> Latn
+    {0x80E00000u, 40u}, // aha -> Latn
+    {0xACE00000u, 40u}, // ahl -> Latn
     {0xB8E00000u,  0u}, // aho -> Ahom
-    {0x616B0000u, 41u}, // ak -> Latn
-    {0xA9400000u, 84u}, // akk -> Xsux
-    {0xB5600000u, 41u}, // aln -> Latn
+    {0x99200000u, 40u}, // ajg -> Latn
+    {0x616B0000u, 40u}, // ak -> Latn
+    {0xA9400000u, 85u}, // akk -> Xsux
+    {0x81600000u, 40u}, // ala -> Latn
+    {0xA1600000u, 40u}, // ali -> Latn
+    {0xB5600000u, 40u}, // aln -> Latn
     {0xCD600000u, 15u}, // alt -> Cyrl
     {0x616D0000u, 18u}, // am -> Ethi
-    {0xB9800000u, 41u}, // amo -> Latn
-    {0xE5C00000u, 41u}, // aoz -> Latn
+    {0xB1800000u, 40u}, // amm -> Latn
+    {0xB5800000u, 40u}, // amn -> Latn
+    {0xB9800000u, 40u}, // amo -> Latn
+    {0xBD800000u, 40u}, // amp -> Latn
+    {0x89A00000u, 40u}, // anc -> Latn
+    {0xA9A00000u, 40u}, // ank -> Latn
+    {0xB5A00000u, 40u}, // ann -> Latn
+    {0xE1A00000u, 40u}, // any -> Latn
+    {0xA5C00000u, 40u}, // aoj -> Latn
+    {0xB1C00000u, 40u}, // aom -> Latn
+    {0xE5C00000u, 40u}, // aoz -> Latn
+    {0x89E00000u,  1u}, // apc -> Arab
+    {0x8DE00000u,  1u}, // apd -> Arab
+    {0x91E00000u, 40u}, // ape -> Latn
+    {0xC5E00000u, 40u}, // apr -> Latn
+    {0xC9E00000u, 40u}, // aps -> Latn
+    {0xE5E00000u, 40u}, // apz -> Latn
     {0x61720000u,  1u}, // ar -> Arab
-    {0x61725842u, 87u}, // ar-XB -> ~~~B
+    {0x61725842u, 88u}, // ar-XB -> ~~~B
     {0x8A200000u,  2u}, // arc -> Armi
-    {0xB6200000u, 41u}, // arn -> Latn
-    {0xBA200000u, 41u}, // aro -> Latn
+    {0x9E200000u, 40u}, // arh -> Latn
+    {0xB6200000u, 40u}, // arn -> Latn
+    {0xBA200000u, 40u}, // aro -> Latn
     {0xC2200000u,  1u}, // arq -> Arab
     {0xE2200000u,  1u}, // ary -> Arab
     {0xE6200000u,  1u}, // arz -> Arab
     {0x61730000u,  7u}, // as -> Beng
-    {0x82400000u, 41u}, // asa -> Latn
+    {0x82400000u, 40u}, // asa -> Latn
     {0x92400000u, 68u}, // ase -> Sgnw
-    {0xCE400000u, 41u}, // ast -> Latn
-    {0xA6600000u, 41u}, // atj -> Latn
+    {0x9A400000u, 40u}, // asg -> Latn
+    {0xBA400000u, 40u}, // aso -> Latn
+    {0xCE400000u, 40u}, // ast -> Latn
+    {0x82600000u, 40u}, // ata -> Latn
+    {0x9A600000u, 40u}, // atg -> Latn
+    {0xA6600000u, 40u}, // atj -> Latn
+    {0xE2800000u, 40u}, // auy -> Latn
     {0x61760000u, 15u}, // av -> Cyrl
+    {0xAEA00000u,  1u}, // avl -> Arab
+    {0xB6A00000u, 40u}, // avn -> Latn
+    {0xCEA00000u, 40u}, // avt -> Latn
+    {0xD2A00000u, 40u}, // avu -> Latn
     {0x82C00000u, 16u}, // awa -> Deva
-    {0x61790000u, 41u}, // ay -> Latn
-    {0x617A0000u, 41u}, // az -> Latn
+    {0x86C00000u, 40u}, // awb -> Latn
+    {0xBAC00000u, 40u}, // awo -> Latn
+    {0xDEC00000u, 40u}, // awx -> Latn
+    {0x61790000u, 40u}, // ay -> Latn
+    {0x87000000u, 40u}, // ayb -> Latn
+    {0x617A0000u, 40u}, // az -> Latn
     {0x617A4951u,  1u}, // az-IQ -> Arab
     {0x617A4952u,  1u}, // az-IR -> Arab
     {0x617A5255u, 15u}, // az-RU -> Cyrl
     {0x62610000u, 15u}, // ba -> Cyrl
     {0xAC010000u,  1u}, // bal -> Arab
-    {0xB4010000u, 41u}, // ban -> Latn
+    {0xB4010000u, 40u}, // ban -> Latn
     {0xBC010000u, 16u}, // bap -> Deva
-    {0xC4010000u, 41u}, // bar -> Latn
-    {0xC8010000u, 41u}, // bas -> Latn
+    {0xC4010000u, 40u}, // bar -> Latn
+    {0xC8010000u, 40u}, // bas -> Latn
+    {0xD4010000u, 40u}, // bav -> Latn
     {0xDC010000u,  5u}, // bax -> Bamu
-    {0x88210000u, 41u}, // bbc -> Latn
-    {0xA4210000u, 41u}, // bbj -> Latn
-    {0xA0410000u, 41u}, // bci -> Latn
+    {0x80210000u, 40u}, // bba -> Latn
+    {0x84210000u, 40u}, // bbb -> Latn
+    {0x88210000u, 40u}, // bbc -> Latn
+    {0x8C210000u, 40u}, // bbd -> Latn
+    {0xA4210000u, 40u}, // bbj -> Latn
+    {0xBC210000u, 40u}, // bbp -> Latn
+    {0xC4210000u, 40u}, // bbr -> Latn
+    {0x94410000u, 40u}, // bcf -> Latn
+    {0x9C410000u, 40u}, // bch -> Latn
+    {0xA0410000u, 40u}, // bci -> Latn
+    {0xB0410000u, 40u}, // bcm -> Latn
+    {0xB4410000u, 40u}, // bcn -> Latn
+    {0xB8410000u, 40u}, // bco -> Latn
+    {0xC0410000u, 18u}, // bcq -> Ethi
+    {0xD0410000u, 40u}, // bcu -> Latn
+    {0x8C610000u, 40u}, // bdd -> Latn
     {0x62650000u, 15u}, // be -> Cyrl
+    {0x94810000u, 40u}, // bef -> Latn
+    {0x9C810000u, 40u}, // beh -> Latn
     {0xA4810000u,  1u}, // bej -> Arab
-    {0xB0810000u, 41u}, // bem -> Latn
-    {0xD8810000u, 41u}, // bew -> Latn
-    {0xE4810000u, 41u}, // bez -> Latn
-    {0x8CA10000u, 41u}, // bfd -> Latn
+    {0xB0810000u, 40u}, // bem -> Latn
+    {0xCC810000u, 40u}, // bet -> Latn
+    {0xD8810000u, 40u}, // bew -> Latn
+    {0xDC810000u, 40u}, // bex -> Latn
+    {0xE4810000u, 40u}, // bez -> Latn
+    {0x8CA10000u, 40u}, // bfd -> Latn
     {0xC0A10000u, 74u}, // bfq -> Taml
     {0xCCA10000u,  1u}, // bft -> Arab
     {0xE0A10000u, 16u}, // bfy -> Deva
@@ -155,663 +224,1202 @@
     {0x88C10000u, 16u}, // bgc -> Deva
     {0xB4C10000u,  1u}, // bgn -> Arab
     {0xDCC10000u, 21u}, // bgx -> Grek
-    {0x62680000u, 38u}, // bh -> Kthi
     {0x84E10000u, 16u}, // bhb -> Deva
+    {0x98E10000u, 40u}, // bhg -> Latn
     {0xA0E10000u, 16u}, // bhi -> Deva
-    {0xA8E10000u, 41u}, // bhk -> Latn
+    {0xA8E10000u, 40u}, // bhk -> Latn
+    {0xACE10000u, 40u}, // bhl -> Latn
     {0xB8E10000u, 16u}, // bho -> Deva
-    {0x62690000u, 41u}, // bi -> Latn
-    {0xA9010000u, 41u}, // bik -> Latn
-    {0xB5010000u, 41u}, // bin -> Latn
+    {0xE0E10000u, 40u}, // bhy -> Latn
+    {0x62690000u, 40u}, // bi -> Latn
+    {0x85010000u, 40u}, // bib -> Latn
+    {0x99010000u, 40u}, // big -> Latn
+    {0xA9010000u, 40u}, // bik -> Latn
+    {0xB1010000u, 40u}, // bim -> Latn
+    {0xB5010000u, 40u}, // bin -> Latn
+    {0xB9010000u, 40u}, // bio -> Latn
+    {0xC1010000u, 40u}, // biq -> Latn
+    {0x9D210000u, 40u}, // bjh -> Latn
+    {0xA1210000u, 18u}, // bji -> Ethi
     {0xA5210000u, 16u}, // bjj -> Deva
-    {0xB5210000u, 41u}, // bjn -> Latn
-    {0xB1410000u, 41u}, // bkm -> Latn
-    {0xD1410000u, 41u}, // bku -> Latn
-    {0xCD610000u, 75u}, // blt -> Tavt
-    {0x626D0000u, 41u}, // bm -> Latn
-    {0xC1810000u, 41u}, // bmq -> Latn
+    {0xB5210000u, 40u}, // bjn -> Latn
+    {0xB9210000u, 40u}, // bjo -> Latn
+    {0xC5210000u, 40u}, // bjr -> Latn
+    {0xE5210000u, 40u}, // bjz -> Latn
+    {0x89410000u, 40u}, // bkc -> Latn
+    {0xB1410000u, 40u}, // bkm -> Latn
+    {0xC1410000u, 40u}, // bkq -> Latn
+    {0xD1410000u, 40u}, // bku -> Latn
+    {0xD5410000u, 40u}, // bkv -> Latn
+    {0xCD610000u, 76u}, // blt -> Tavt
+    {0x626D0000u, 40u}, // bm -> Latn
+    {0x9D810000u, 40u}, // bmh -> Latn
+    {0xA9810000u, 40u}, // bmk -> Latn
+    {0xC1810000u, 40u}, // bmq -> Latn
+    {0xD1810000u, 40u}, // bmu -> Latn
     {0x626E0000u,  7u}, // bn -> Beng
-    {0x626F0000u, 80u}, // bo -> Tibt
+    {0x99A10000u, 40u}, // bng -> Latn
+    {0xB1A10000u, 40u}, // bnm -> Latn
+    {0xBDA10000u, 40u}, // bnp -> Latn
+    {0x626F0000u, 81u}, // bo -> Tibt
+    {0xA5C10000u, 40u}, // boj -> Latn
+    {0xB1C10000u, 40u}, // bom -> Latn
+    {0xB5C10000u, 40u}, // bon -> Latn
     {0xE1E10000u,  7u}, // bpy -> Beng
+    {0x8A010000u, 40u}, // bqc -> Latn
     {0xA2010000u,  1u}, // bqi -> Arab
-    {0xD6010000u, 41u}, // bqv -> Latn
-    {0x62720000u, 41u}, // br -> Latn
+    {0xBE010000u, 40u}, // bqp -> Latn
+    {0xD6010000u, 40u}, // bqv -> Latn
+    {0x62720000u, 40u}, // br -> Latn
     {0x82210000u, 16u}, // bra -> Deva
     {0x9E210000u,  1u}, // brh -> Arab
     {0xDE210000u, 16u}, // brx -> Deva
-    {0x62730000u, 41u}, // bs -> Latn
+    {0xE6210000u, 40u}, // brz -> Latn
+    {0x62730000u, 40u}, // bs -> Latn
+    {0xA6410000u, 40u}, // bsj -> Latn
     {0xC2410000u,  6u}, // bsq -> Bass
-    {0xCA410000u, 41u}, // bss -> Latn
-    {0xBA610000u, 41u}, // bto -> Latn
+    {0xCA410000u, 40u}, // bss -> Latn
+    {0xCE410000u, 18u}, // bst -> Ethi
+    {0xBA610000u, 40u}, // bto -> Latn
+    {0xCE610000u, 40u}, // btt -> Latn
     {0xD6610000u, 16u}, // btv -> Deva
     {0x82810000u, 15u}, // bua -> Cyrl
-    {0x8A810000u, 41u}, // buc -> Latn
-    {0x9A810000u, 41u}, // bug -> Latn
-    {0xB2810000u, 41u}, // bum -> Latn
-    {0x86A10000u, 41u}, // bvb -> Latn
+    {0x8A810000u, 40u}, // buc -> Latn
+    {0x8E810000u, 40u}, // bud -> Latn
+    {0x9A810000u, 40u}, // bug -> Latn
+    {0xAA810000u, 40u}, // buk -> Latn
+    {0xB2810000u, 40u}, // bum -> Latn
+    {0xBA810000u, 40u}, // buo -> Latn
+    {0xCA810000u, 40u}, // bus -> Latn
+    {0xD2810000u, 40u}, // buu -> Latn
+    {0x86A10000u, 40u}, // bvb -> Latn
+    {0x8EC10000u, 40u}, // bwd -> Latn
+    {0xC6C10000u, 40u}, // bwr -> Latn
+    {0x9EE10000u, 40u}, // bxh -> Latn
+    {0x93010000u, 40u}, // bye -> Latn
     {0xB7010000u, 18u}, // byn -> Ethi
-    {0xD7010000u, 41u}, // byv -> Latn
-    {0x93210000u, 41u}, // bze -> Latn
-    {0x63610000u, 41u}, // ca -> Latn
-    {0x9C420000u, 41u}, // cch -> Latn
+    {0xC7010000u, 40u}, // byr -> Latn
+    {0xCB010000u, 40u}, // bys -> Latn
+    {0xD7010000u, 40u}, // byv -> Latn
+    {0xDF010000u, 40u}, // byx -> Latn
+    {0x83210000u, 40u}, // bza -> Latn
+    {0x93210000u, 40u}, // bze -> Latn
+    {0x97210000u, 40u}, // bzf -> Latn
+    {0x9F210000u, 40u}, // bzh -> Latn
+    {0xDB210000u, 40u}, // bzw -> Latn
+    {0x63610000u, 40u}, // ca -> Latn
+    {0xB4020000u, 40u}, // can -> Latn
+    {0xA4220000u, 40u}, // cbj -> Latn
+    {0x9C420000u, 40u}, // cch -> Latn
     {0xBC420000u,  7u}, // ccp -> Beng
     {0x63650000u, 15u}, // ce -> Cyrl
-    {0x84820000u, 41u}, // ceb -> Latn
-    {0x98C20000u, 41u}, // cgg -> Latn
-    {0x63680000u, 41u}, // ch -> Latn
-    {0xA8E20000u, 41u}, // chk -> Latn
+    {0x84820000u, 40u}, // ceb -> Latn
+    {0x80A20000u, 40u}, // cfa -> Latn
+    {0x98C20000u, 40u}, // cgg -> Latn
+    {0x63680000u, 40u}, // ch -> Latn
+    {0xA8E20000u, 40u}, // chk -> Latn
     {0xB0E20000u, 15u}, // chm -> Cyrl
-    {0xB8E20000u, 41u}, // cho -> Latn
-    {0xBCE20000u, 41u}, // chp -> Latn
+    {0xB8E20000u, 40u}, // cho -> Latn
+    {0xBCE20000u, 40u}, // chp -> Latn
     {0xC4E20000u, 12u}, // chr -> Cher
     {0x81220000u,  1u}, // cja -> Arab
     {0xB1220000u, 11u}, // cjm -> Cham
+    {0xD5220000u, 40u}, // cjv -> Latn
     {0x85420000u,  1u}, // ckb -> Arab
-    {0x636F0000u, 41u}, // co -> Latn
+    {0xAD420000u, 40u}, // ckl -> Latn
+    {0xB9420000u, 40u}, // cko -> Latn
+    {0xE1420000u, 40u}, // cky -> Latn
+    {0x81620000u, 40u}, // cla -> Latn
+    {0x91820000u, 40u}, // cme -> Latn
+    {0x636F0000u, 40u}, // co -> Latn
     {0xBDC20000u, 13u}, // cop -> Copt
-    {0xC9E20000u, 41u}, // cps -> Latn
+    {0xC9E20000u, 40u}, // cps -> Latn
     {0x63720000u,  9u}, // cr -> Cans
     {0xA6220000u,  9u}, // crj -> Cans
     {0xAA220000u,  9u}, // crk -> Cans
     {0xAE220000u,  9u}, // crl -> Cans
     {0xB2220000u,  9u}, // crm -> Cans
-    {0xCA220000u, 41u}, // crs -> Latn
-    {0x63730000u, 41u}, // cs -> Latn
-    {0x86420000u, 41u}, // csb -> Latn
+    {0xCA220000u, 40u}, // crs -> Latn
+    {0x63730000u, 40u}, // cs -> Latn
+    {0x86420000u, 40u}, // csb -> Latn
     {0xDA420000u,  9u}, // csw -> Cans
     {0x8E620000u, 59u}, // ctd -> Pauc
     {0x63750000u, 15u}, // cu -> Cyrl
     {0x63760000u, 15u}, // cv -> Cyrl
-    {0x63790000u, 41u}, // cy -> Latn
-    {0x64610000u, 41u}, // da -> Latn
-    {0xA8030000u, 41u}, // dak -> Latn
+    {0x63790000u, 40u}, // cy -> Latn
+    {0x64610000u, 40u}, // da -> Latn
+    {0x8C030000u, 40u}, // dad -> Latn
+    {0x94030000u, 40u}, // daf -> Latn
+    {0x98030000u, 40u}, // dag -> Latn
+    {0x9C030000u, 40u}, // dah -> Latn
+    {0xA8030000u, 40u}, // dak -> Latn
     {0xC4030000u, 15u}, // dar -> Cyrl
-    {0xD4030000u, 41u}, // dav -> Latn
+    {0xD4030000u, 40u}, // dav -> Latn
+    {0x8C230000u, 40u}, // dbd -> Latn
+    {0xC0230000u, 40u}, // dbq -> Latn
     {0x88430000u,  1u}, // dcc -> Arab
-    {0x64650000u, 41u}, // de -> Latn
-    {0xB4830000u, 41u}, // den -> Latn
-    {0xC4C30000u, 41u}, // dgr -> Latn
-    {0x91230000u, 41u}, // dje -> Latn
-    {0xA5A30000u, 41u}, // dnj -> Latn
+    {0xB4630000u, 40u}, // ddn -> Latn
+    {0x64650000u, 40u}, // de -> Latn
+    {0x8C830000u, 40u}, // ded -> Latn
+    {0xB4830000u, 40u}, // den -> Latn
+    {0x80C30000u, 40u}, // dga -> Latn
+    {0x9CC30000u, 40u}, // dgh -> Latn
+    {0xA0C30000u, 40u}, // dgi -> Latn
+    {0xACC30000u,  1u}, // dgl -> Arab
+    {0xC4C30000u, 40u}, // dgr -> Latn
+    {0xE4C30000u, 40u}, // dgz -> Latn
+    {0x81030000u, 40u}, // dia -> Latn
+    {0x91230000u, 40u}, // dje -> Latn
+    {0xA5A30000u, 40u}, // dnj -> Latn
+    {0x85C30000u, 40u}, // dob -> Latn
     {0xA1C30000u,  1u}, // doi -> Arab
-    {0x86430000u, 41u}, // dsb -> Latn
-    {0xB2630000u, 41u}, // dtm -> Latn
-    {0xBE630000u, 41u}, // dtp -> Latn
-    {0x82830000u, 41u}, // dua -> Latn
-    {0x64760000u, 78u}, // dv -> Thaa
-    {0xBB030000u, 41u}, // dyo -> Latn
-    {0xD3030000u, 41u}, // dyu -> Latn
-    {0x647A0000u, 80u}, // dz -> Tibt
-    {0xD0240000u, 41u}, // ebu -> Latn
-    {0x65650000u, 41u}, // ee -> Latn
-    {0xA0A40000u, 41u}, // efi -> Latn
-    {0xACC40000u, 41u}, // egl -> Latn
+    {0xBDC30000u, 40u}, // dop -> Latn
+    {0xD9C30000u, 40u}, // dow -> Latn
+    {0xA2230000u, 40u}, // dri -> Latn
+    {0xCA230000u, 18u}, // drs -> Ethi
+    {0x86430000u, 40u}, // dsb -> Latn
+    {0xB2630000u, 40u}, // dtm -> Latn
+    {0xBE630000u, 40u}, // dtp -> Latn
+    {0xCA630000u, 40u}, // dts -> Latn
+    {0xE2630000u, 16u}, // dty -> Deva
+    {0x82830000u, 40u}, // dua -> Latn
+    {0x8A830000u, 40u}, // duc -> Latn
+    {0x8E830000u, 40u}, // dud -> Latn
+    {0x9A830000u, 40u}, // dug -> Latn
+    {0x64760000u, 79u}, // dv -> Thaa
+    {0x82A30000u, 40u}, // dva -> Latn
+    {0xDAC30000u, 40u}, // dww -> Latn
+    {0xBB030000u, 40u}, // dyo -> Latn
+    {0xD3030000u, 40u}, // dyu -> Latn
+    {0x647A0000u, 81u}, // dz -> Tibt
+    {0x9B230000u, 40u}, // dzg -> Latn
+    {0xD0240000u, 40u}, // ebu -> Latn
+    {0x65650000u, 40u}, // ee -> Latn
+    {0xA0A40000u, 40u}, // efi -> Latn
+    {0xACC40000u, 40u}, // egl -> Latn
     {0xE0C40000u, 17u}, // egy -> Egyp
     {0xE1440000u, 32u}, // eky -> Kali
     {0x656C0000u, 21u}, // el -> Grek
-    {0x656E0000u, 41u}, // en -> Latn
-    {0x656E5841u, 86u}, // en-XA -> ~~~A
-    {0x656F0000u, 41u}, // eo -> Latn
-    {0x65730000u, 41u}, // es -> Latn
-    {0xD2440000u, 41u}, // esu -> Latn
-    {0x65740000u, 41u}, // et -> Latn
+    {0x81840000u, 40u}, // ema -> Latn
+    {0xA1840000u, 40u}, // emi -> Latn
+    {0x656E0000u, 40u}, // en -> Latn
+    {0x656E5841u, 87u}, // en-XA -> ~~~A
+    {0xB5A40000u, 40u}, // enn -> Latn
+    {0xC1A40000u, 40u}, // enq -> Latn
+    {0x656F0000u, 40u}, // eo -> Latn
+    {0xA2240000u, 40u}, // eri -> Latn
+    {0x65730000u, 40u}, // es -> Latn
+    {0xD2440000u, 40u}, // esu -> Latn
+    {0x65740000u, 40u}, // et -> Latn
+    {0xC6640000u, 40u}, // etr -> Latn
     {0xCE640000u, 30u}, // ett -> Ital
-    {0x65750000u, 41u}, // eu -> Latn
-    {0xBAC40000u, 41u}, // ewo -> Latn
-    {0xCEE40000u, 41u}, // ext -> Latn
+    {0xD2640000u, 40u}, // etu -> Latn
+    {0xDE640000u, 40u}, // etx -> Latn
+    {0x65750000u, 40u}, // eu -> Latn
+    {0xBAC40000u, 40u}, // ewo -> Latn
+    {0xCEE40000u, 40u}, // ext -> Latn
     {0x66610000u,  1u}, // fa -> Arab
-    {0xB4050000u, 41u}, // fan -> Latn
-    {0x66660000u, 41u}, // ff -> Latn
-    {0xB0A50000u, 41u}, // ffm -> Latn
-    {0x66690000u, 41u}, // fi -> Latn
+    {0x80050000u, 40u}, // faa -> Latn
+    {0x84050000u, 40u}, // fab -> Latn
+    {0x98050000u, 40u}, // fag -> Latn
+    {0xA0050000u, 40u}, // fai -> Latn
+    {0xB4050000u, 40u}, // fan -> Latn
+    {0x66660000u, 40u}, // ff -> Latn
+    {0xA0A50000u, 40u}, // ffi -> Latn
+    {0xB0A50000u, 40u}, // ffm -> Latn
+    {0x66690000u, 40u}, // fi -> Latn
     {0x81050000u,  1u}, // fia -> Arab
-    {0xAD050000u, 41u}, // fil -> Latn
-    {0xCD050000u, 41u}, // fit -> Latn
-    {0x666A0000u, 41u}, // fj -> Latn
-    {0x666F0000u, 41u}, // fo -> Latn
-    {0xB5C50000u, 41u}, // fon -> Latn
-    {0x66720000u, 41u}, // fr -> Latn
-    {0x8A250000u, 41u}, // frc -> Latn
-    {0xBE250000u, 41u}, // frp -> Latn
-    {0xC6250000u, 41u}, // frr -> Latn
-    {0xCA250000u, 41u}, // frs -> Latn
-    {0x8E850000u, 41u}, // fud -> Latn
-    {0xC2850000u, 41u}, // fuq -> Latn
-    {0xC6850000u, 41u}, // fur -> Latn
-    {0xD6850000u, 41u}, // fuv -> Latn
-    {0xC6A50000u, 41u}, // fvr -> Latn
-    {0x66790000u, 41u}, // fy -> Latn
-    {0x67610000u, 41u}, // ga -> Latn
-    {0x80060000u, 41u}, // gaa -> Latn
-    {0x98060000u, 41u}, // gag -> Latn
+    {0xAD050000u, 40u}, // fil -> Latn
+    {0xCD050000u, 40u}, // fit -> Latn
+    {0x666A0000u, 40u}, // fj -> Latn
+    {0xC5650000u, 40u}, // flr -> Latn
+    {0xBD850000u, 40u}, // fmp -> Latn
+    {0x666F0000u, 40u}, // fo -> Latn
+    {0x8DC50000u, 40u}, // fod -> Latn
+    {0xB5C50000u, 40u}, // fon -> Latn
+    {0xC5C50000u, 40u}, // for -> Latn
+    {0x91E50000u, 40u}, // fpe -> Latn
+    {0xCA050000u, 40u}, // fqs -> Latn
+    {0x66720000u, 40u}, // fr -> Latn
+    {0x8A250000u, 40u}, // frc -> Latn
+    {0xBE250000u, 40u}, // frp -> Latn
+    {0xC6250000u, 40u}, // frr -> Latn
+    {0xCA250000u, 40u}, // frs -> Latn
+    {0x86850000u,  1u}, // fub -> Arab
+    {0x8E850000u, 40u}, // fud -> Latn
+    {0x92850000u, 40u}, // fue -> Latn
+    {0x96850000u, 40u}, // fuf -> Latn
+    {0x9E850000u, 40u}, // fuh -> Latn
+    {0xC2850000u, 40u}, // fuq -> Latn
+    {0xC6850000u, 40u}, // fur -> Latn
+    {0xD6850000u, 40u}, // fuv -> Latn
+    {0xE2850000u, 40u}, // fuy -> Latn
+    {0xC6A50000u, 40u}, // fvr -> Latn
+    {0x66790000u, 40u}, // fy -> Latn
+    {0x67610000u, 40u}, // ga -> Latn
+    {0x80060000u, 40u}, // gaa -> Latn
+    {0x94060000u, 40u}, // gaf -> Latn
+    {0x98060000u, 40u}, // gag -> Latn
+    {0x9C060000u, 40u}, // gah -> Latn
+    {0xA4060000u, 40u}, // gaj -> Latn
+    {0xB0060000u, 40u}, // gam -> Latn
     {0xB4060000u, 24u}, // gan -> Hans
-    {0xE0060000u, 41u}, // gay -> Latn
+    {0xD8060000u, 40u}, // gaw -> Latn
+    {0xE0060000u, 40u}, // gay -> Latn
+    {0x94260000u, 40u}, // gbf -> Latn
     {0xB0260000u, 16u}, // gbm -> Deva
+    {0xE0260000u, 40u}, // gby -> Latn
     {0xE4260000u,  1u}, // gbz -> Arab
-    {0xC4460000u, 41u}, // gcr -> Latn
-    {0x67640000u, 41u}, // gd -> Latn
+    {0xC4460000u, 40u}, // gcr -> Latn
+    {0x67640000u, 40u}, // gd -> Latn
+    {0x90660000u, 40u}, // gde -> Latn
+    {0xB4660000u, 40u}, // gdn -> Latn
+    {0xC4660000u, 40u}, // gdr -> Latn
+    {0x84860000u, 40u}, // geb -> Latn
+    {0xA4860000u, 40u}, // gej -> Latn
+    {0xAC860000u, 40u}, // gel -> Latn
     {0xE4860000u, 18u}, // gez -> Ethi
+    {0xA8A60000u, 40u}, // gfk -> Latn
     {0xB4C60000u, 16u}, // ggn -> Deva
-    {0xAD060000u, 41u}, // gil -> Latn
+    {0xC8E60000u, 40u}, // ghs -> Latn
+    {0xAD060000u, 40u}, // gil -> Latn
+    {0xB1060000u, 40u}, // gim -> Latn
     {0xA9260000u,  1u}, // gjk -> Arab
+    {0xB5260000u, 40u}, // gjn -> Latn
     {0xD1260000u,  1u}, // gju -> Arab
-    {0x676C0000u, 41u}, // gl -> Latn
+    {0xB5460000u, 40u}, // gkn -> Latn
+    {0xBD460000u, 40u}, // gkp -> Latn
+    {0x676C0000u, 40u}, // gl -> Latn
     {0xA9660000u,  1u}, // glk -> Arab
-    {0x676E0000u, 41u}, // gn -> Latn
+    {0xB1860000u, 40u}, // gmm -> Latn
+    {0xD5860000u, 18u}, // gmv -> Ethi
+    {0x676E0000u, 40u}, // gn -> Latn
+    {0x8DA60000u, 40u}, // gnd -> Latn
+    {0x99A60000u, 40u}, // gng -> Latn
+    {0x8DC60000u, 40u}, // god -> Latn
+    {0x95C60000u, 18u}, // gof -> Ethi
+    {0xA1C60000u, 40u}, // goi -> Latn
     {0xB1C60000u, 16u}, // gom -> Deva
-    {0xB5C60000u, 76u}, // gon -> Telu
-    {0xC5C60000u, 41u}, // gor -> Latn
-    {0xC9C60000u, 41u}, // gos -> Latn
+    {0xB5C60000u, 77u}, // gon -> Telu
+    {0xC5C60000u, 40u}, // gor -> Latn
+    {0xC9C60000u, 40u}, // gos -> Latn
     {0xCDC60000u, 20u}, // got -> Goth
     {0x8A260000u, 14u}, // grc -> Cprt
     {0xCE260000u,  7u}, // grt -> Beng
-    {0xDA460000u, 41u}, // gsw -> Latn
+    {0xDA260000u, 40u}, // grw -> Latn
+    {0xDA460000u, 40u}, // gsw -> Latn
     {0x67750000u, 22u}, // gu -> Gujr
-    {0x86860000u, 41u}, // gub -> Latn
-    {0x8A860000u, 41u}, // guc -> Latn
-    {0xC6860000u, 41u}, // gur -> Latn
-    {0xE6860000u, 41u}, // guz -> Latn
-    {0x67760000u, 41u}, // gv -> Latn
+    {0x86860000u, 40u}, // gub -> Latn
+    {0x8A860000u, 40u}, // guc -> Latn
+    {0x8E860000u, 40u}, // gud -> Latn
+    {0xC6860000u, 40u}, // gur -> Latn
+    {0xDA860000u, 40u}, // guw -> Latn
+    {0xDE860000u, 40u}, // gux -> Latn
+    {0xE6860000u, 40u}, // guz -> Latn
+    {0x67760000u, 40u}, // gv -> Latn
+    {0x96A60000u, 40u}, // gvf -> Latn
     {0xC6A60000u, 16u}, // gvr -> Deva
-    {0xA2C60000u, 41u}, // gwi -> Latn
-    {0x68610000u, 41u}, // ha -> Latn
+    {0xCAA60000u, 40u}, // gvs -> Latn
+    {0x8AC60000u,  1u}, // gwc -> Arab
+    {0xA2C60000u, 40u}, // gwi -> Latn
+    {0xCEC60000u,  1u}, // gwt -> Arab
+    {0xA3060000u, 40u}, // gyi -> Latn
+    {0x68610000u, 40u}, // ha -> Latn
     {0x6861434Du,  1u}, // ha-CM -> Arab
     {0x68615344u,  1u}, // ha-SD -> Arab
+    {0x98070000u, 40u}, // hag -> Latn
     {0xA8070000u, 24u}, // hak -> Hans
-    {0xD8070000u, 41u}, // haw -> Latn
+    {0xB0070000u, 40u}, // ham -> Latn
+    {0xD8070000u, 40u}, // haw -> Latn
     {0xE4070000u,  1u}, // haz -> Arab
+    {0x84270000u, 40u}, // hbb -> Latn
+    {0xE0670000u, 18u}, // hdy -> Ethi
     {0x68650000u, 27u}, // he -> Hebr
+    {0xE0E70000u, 40u}, // hhy -> Latn
     {0x68690000u, 16u}, // hi -> Deva
-    {0x95070000u, 41u}, // hif -> Latn
-    {0xAD070000u, 41u}, // hil -> Latn
+    {0x81070000u, 40u}, // hia -> Latn
+    {0x95070000u, 40u}, // hif -> Latn
+    {0x99070000u, 40u}, // hig -> Latn
+    {0x9D070000u, 40u}, // hih -> Latn
+    {0xAD070000u, 40u}, // hil -> Latn
+    {0x81670000u, 40u}, // hla -> Latn
     {0xD1670000u, 28u}, // hlu -> Hluw
     {0x8D870000u, 62u}, // hmd -> Plrd
+    {0xCD870000u, 40u}, // hmt -> Latn
     {0x8DA70000u,  1u}, // hnd -> Arab
     {0x91A70000u, 16u}, // hne -> Deva
     {0xA5A70000u, 29u}, // hnj -> Hmng
-    {0xB5A70000u, 41u}, // hnn -> Latn
+    {0xB5A70000u, 40u}, // hnn -> Latn
     {0xB9A70000u,  1u}, // hno -> Arab
-    {0x686F0000u, 41u}, // ho -> Latn
+    {0x686F0000u, 40u}, // ho -> Latn
     {0x89C70000u, 16u}, // hoc -> Deva
     {0xA5C70000u, 16u}, // hoj -> Deva
-    {0x68720000u, 41u}, // hr -> Latn
-    {0x86470000u, 41u}, // hsb -> Latn
+    {0xCDC70000u, 40u}, // hot -> Latn
+    {0x68720000u, 40u}, // hr -> Latn
+    {0x86470000u, 40u}, // hsb -> Latn
     {0xB6470000u, 24u}, // hsn -> Hans
-    {0x68740000u, 41u}, // ht -> Latn
-    {0x68750000u, 41u}, // hu -> Latn
+    {0x68740000u, 40u}, // ht -> Latn
+    {0x68750000u, 40u}, // hu -> Latn
+    {0xA2870000u, 40u}, // hui -> Latn
     {0x68790000u,  3u}, // hy -> Armn
-    {0x687A0000u, 41u}, // hz -> Latn
-    {0x69610000u, 41u}, // ia -> Latn
-    {0x80280000u, 41u}, // iba -> Latn
-    {0x84280000u, 41u}, // ibb -> Latn
-    {0x69640000u, 41u}, // id -> Latn
-    {0x69670000u, 41u}, // ig -> Latn
-    {0x69690000u, 85u}, // ii -> Yiii
-    {0x696B0000u, 41u}, // ik -> Latn
-    {0xCD480000u, 41u}, // ikt -> Latn
-    {0xB9680000u, 41u}, // ilo -> Latn
-    {0x696E0000u, 41u}, // in -> Latn
+    {0x687A0000u, 40u}, // hz -> Latn
+    {0x69610000u, 40u}, // ia -> Latn
+    {0xB4080000u, 40u}, // ian -> Latn
+    {0xC4080000u, 40u}, // iar -> Latn
+    {0x80280000u, 40u}, // iba -> Latn
+    {0x84280000u, 40u}, // ibb -> Latn
+    {0xE0280000u, 40u}, // iby -> Latn
+    {0x80480000u, 40u}, // ica -> Latn
+    {0x9C480000u, 40u}, // ich -> Latn
+    {0x69640000u, 40u}, // id -> Latn
+    {0x8C680000u, 40u}, // idd -> Latn
+    {0xA0680000u, 40u}, // idi -> Latn
+    {0xD0680000u, 40u}, // idu -> Latn
+    {0x69670000u, 40u}, // ig -> Latn
+    {0x84C80000u, 40u}, // igb -> Latn
+    {0x90C80000u, 40u}, // ige -> Latn
+    {0x69690000u, 86u}, // ii -> Yiii
+    {0xA5280000u, 40u}, // ijj -> Latn
+    {0x696B0000u, 40u}, // ik -> Latn
+    {0xA9480000u, 40u}, // ikk -> Latn
+    {0xCD480000u, 40u}, // ikt -> Latn
+    {0xD9480000u, 40u}, // ikw -> Latn
+    {0xDD480000u, 40u}, // ikx -> Latn
+    {0xB9680000u, 40u}, // ilo -> Latn
+    {0xB9880000u, 40u}, // imo -> Latn
+    {0x696E0000u, 40u}, // in -> Latn
     {0x9DA80000u, 15u}, // inh -> Cyrl
-    {0x69730000u, 41u}, // is -> Latn
-    {0x69740000u, 41u}, // it -> Latn
+    {0xD1C80000u, 40u}, // iou -> Latn
+    {0xA2280000u, 40u}, // iri -> Latn
+    {0x69730000u, 40u}, // is -> Latn
+    {0x69740000u, 40u}, // it -> Latn
     {0x69750000u,  9u}, // iu -> Cans
     {0x69770000u, 27u}, // iw -> Hebr
-    {0x9F280000u, 41u}, // izh -> Latn
+    {0xB2C80000u, 40u}, // iwm -> Latn
+    {0xCAC80000u, 40u}, // iws -> Latn
+    {0x9F280000u, 40u}, // izh -> Latn
+    {0xA3280000u, 40u}, // izi -> Latn
     {0x6A610000u, 31u}, // ja -> Jpan
-    {0xB0090000u, 41u}, // jam -> Latn
-    {0xB8C90000u, 41u}, // jgo -> Latn
+    {0x84090000u, 40u}, // jab -> Latn
+    {0xB0090000u, 40u}, // jam -> Latn
+    {0xD0290000u, 40u}, // jbu -> Latn
+    {0xB4890000u, 40u}, // jen -> Latn
+    {0xA8C90000u, 40u}, // jgk -> Latn
+    {0xB8C90000u, 40u}, // jgo -> Latn
     {0x6A690000u, 27u}, // ji -> Hebr
-    {0x89890000u, 41u}, // jmc -> Latn
+    {0x85090000u, 40u}, // jib -> Latn
+    {0x89890000u, 40u}, // jmc -> Latn
     {0xAD890000u, 16u}, // jml -> Deva
-    {0xCE890000u, 41u}, // jut -> Latn
-    {0x6A760000u, 41u}, // jv -> Latn
-    {0x6A770000u, 41u}, // jw -> Latn
+    {0x82290000u, 40u}, // jra -> Latn
+    {0xCE890000u, 40u}, // jut -> Latn
+    {0x6A760000u, 40u}, // jv -> Latn
+    {0x6A770000u, 40u}, // jw -> Latn
     {0x6B610000u, 19u}, // ka -> Geor
     {0x800A0000u, 15u}, // kaa -> Cyrl
-    {0x840A0000u, 41u}, // kab -> Latn
-    {0x880A0000u, 41u}, // kac -> Latn
-    {0xA40A0000u, 41u}, // kaj -> Latn
-    {0xB00A0000u, 41u}, // kam -> Latn
-    {0xB80A0000u, 41u}, // kao -> Latn
+    {0x840A0000u, 40u}, // kab -> Latn
+    {0x880A0000u, 40u}, // kac -> Latn
+    {0x8C0A0000u, 40u}, // kad -> Latn
+    {0xA00A0000u, 40u}, // kai -> Latn
+    {0xA40A0000u, 40u}, // kaj -> Latn
+    {0xB00A0000u, 40u}, // kam -> Latn
+    {0xB80A0000u, 40u}, // kao -> Latn
     {0x8C2A0000u, 15u}, // kbd -> Cyrl
-    {0x984A0000u, 41u}, // kcg -> Latn
-    {0xA84A0000u, 41u}, // kck -> Latn
-    {0x906A0000u, 41u}, // kde -> Latn
-    {0xCC6A0000u, 79u}, // kdt -> Thai
-    {0x808A0000u, 41u}, // kea -> Latn
-    {0xB48A0000u, 41u}, // ken -> Latn
-    {0xB8AA0000u, 41u}, // kfo -> Latn
+    {0xB02A0000u, 40u}, // kbm -> Latn
+    {0xBC2A0000u, 40u}, // kbp -> Latn
+    {0xC02A0000u, 40u}, // kbq -> Latn
+    {0xDC2A0000u, 40u}, // kbx -> Latn
+    {0xE02A0000u,  1u}, // kby -> Arab
+    {0x984A0000u, 40u}, // kcg -> Latn
+    {0xA84A0000u, 40u}, // kck -> Latn
+    {0xAC4A0000u, 40u}, // kcl -> Latn
+    {0xCC4A0000u, 40u}, // kct -> Latn
+    {0x906A0000u, 40u}, // kde -> Latn
+    {0x9C6A0000u,  1u}, // kdh -> Arab
+    {0xAC6A0000u, 40u}, // kdl -> Latn
+    {0xCC6A0000u, 80u}, // kdt -> Thai
+    {0x808A0000u, 40u}, // kea -> Latn
+    {0xB48A0000u, 40u}, // ken -> Latn
+    {0xE48A0000u, 40u}, // kez -> Latn
+    {0xB8AA0000u, 40u}, // kfo -> Latn
     {0xC4AA0000u, 16u}, // kfr -> Deva
     {0xE0AA0000u, 16u}, // kfy -> Deva
-    {0x6B670000u, 41u}, // kg -> Latn
-    {0x90CA0000u, 41u}, // kge -> Latn
-    {0xBCCA0000u, 41u}, // kgp -> Latn
-    {0x80EA0000u, 41u}, // kha -> Latn
+    {0x6B670000u, 40u}, // kg -> Latn
+    {0x90CA0000u, 40u}, // kge -> Latn
+    {0x94CA0000u, 40u}, // kgf -> Latn
+    {0xBCCA0000u, 40u}, // kgp -> Latn
+    {0x80EA0000u, 40u}, // kha -> Latn
     {0x84EA0000u, 73u}, // khb -> Talu
     {0xB4EA0000u, 16u}, // khn -> Deva
-    {0xC0EA0000u, 41u}, // khq -> Latn
-    {0xCCEA0000u, 53u}, // kht -> Mymr
+    {0xC0EA0000u, 40u}, // khq -> Latn
+    {0xC8EA0000u, 40u}, // khs -> Latn
+    {0xCCEA0000u, 52u}, // kht -> Mymr
     {0xD8EA0000u,  1u}, // khw -> Arab
-    {0x6B690000u, 41u}, // ki -> Latn
-    {0xD10A0000u, 41u}, // kiu -> Latn
-    {0x6B6A0000u, 41u}, // kj -> Latn
-    {0x992A0000u, 40u}, // kjg -> Laoo
+    {0xE4EA0000u, 40u}, // khz -> Latn
+    {0x6B690000u, 40u}, // ki -> Latn
+    {0xA50A0000u, 40u}, // kij -> Latn
+    {0xD10A0000u, 40u}, // kiu -> Latn
+    {0xD90A0000u, 40u}, // kiw -> Latn
+    {0x6B6A0000u, 40u}, // kj -> Latn
+    {0x8D2A0000u, 40u}, // kjd -> Latn
+    {0x992A0000u, 39u}, // kjg -> Laoo
+    {0xC92A0000u, 40u}, // kjs -> Latn
+    {0xE12A0000u, 40u}, // kjy -> Latn
     {0x6B6B0000u, 15u}, // kk -> Cyrl
     {0x6B6B4146u,  1u}, // kk-AF -> Arab
     {0x6B6B434Eu,  1u}, // kk-CN -> Arab
     {0x6B6B4952u,  1u}, // kk-IR -> Arab
     {0x6B6B4D4Eu,  1u}, // kk-MN -> Arab
-    {0xA54A0000u, 41u}, // kkj -> Latn
-    {0x6B6C0000u, 41u}, // kl -> Latn
-    {0xB56A0000u, 41u}, // kln -> Latn
+    {0x894A0000u, 40u}, // kkc -> Latn
+    {0xA54A0000u, 40u}, // kkj -> Latn
+    {0x6B6C0000u, 40u}, // kl -> Latn
+    {0xB56A0000u, 40u}, // kln -> Latn
+    {0xC16A0000u, 40u}, // klq -> Latn
+    {0xCD6A0000u, 40u}, // klt -> Latn
+    {0xDD6A0000u, 40u}, // klx -> Latn
     {0x6B6D0000u, 35u}, // km -> Khmr
-    {0x858A0000u, 41u}, // kmb -> Latn
+    {0x858A0000u, 40u}, // kmb -> Latn
+    {0x9D8A0000u, 40u}, // kmh -> Latn
+    {0xB98A0000u, 40u}, // kmo -> Latn
+    {0xC98A0000u, 40u}, // kms -> Latn
+    {0xD18A0000u, 40u}, // kmu -> Latn
+    {0xD98A0000u, 40u}, // kmw -> Latn
     {0x6B6E0000u, 36u}, // kn -> Knda
+    {0xBDAA0000u, 40u}, // knp -> Latn
     {0x6B6F0000u, 37u}, // ko -> Kore
     {0xA1CA0000u, 15u}, // koi -> Cyrl
     {0xA9CA0000u, 16u}, // kok -> Deva
-    {0xC9CA0000u, 41u}, // kos -> Latn
-    {0x91EA0000u, 41u}, // kpe -> Latn
+    {0xADCA0000u, 40u}, // kol -> Latn
+    {0xC9CA0000u, 40u}, // kos -> Latn
+    {0xE5CA0000u, 40u}, // koz -> Latn
+    {0x91EA0000u, 40u}, // kpe -> Latn
+    {0x95EA0000u, 40u}, // kpf -> Latn
+    {0xB9EA0000u, 40u}, // kpo -> Latn
+    {0xC5EA0000u, 40u}, // kpr -> Latn
+    {0xDDEA0000u, 40u}, // kpx -> Latn
+    {0x860A0000u, 40u}, // kqb -> Latn
+    {0x960A0000u, 40u}, // kqf -> Latn
+    {0xCA0A0000u, 40u}, // kqs -> Latn
+    {0xE20A0000u, 18u}, // kqy -> Ethi
     {0x8A2A0000u, 15u}, // krc -> Cyrl
-    {0xA22A0000u, 41u}, // kri -> Latn
-    {0xA62A0000u, 41u}, // krj -> Latn
-    {0xAE2A0000u, 41u}, // krl -> Latn
+    {0xA22A0000u, 40u}, // kri -> Latn
+    {0xA62A0000u, 40u}, // krj -> Latn
+    {0xAE2A0000u, 40u}, // krl -> Latn
+    {0xCA2A0000u, 40u}, // krs -> Latn
     {0xD22A0000u, 16u}, // kru -> Deva
     {0x6B730000u,  1u}, // ks -> Arab
-    {0x864A0000u, 41u}, // ksb -> Latn
-    {0x964A0000u, 41u}, // ksf -> Latn
-    {0x9E4A0000u, 41u}, // ksh -> Latn
-    {0x6B750000u, 41u}, // ku -> Latn
+    {0x864A0000u, 40u}, // ksb -> Latn
+    {0x8E4A0000u, 40u}, // ksd -> Latn
+    {0x964A0000u, 40u}, // ksf -> Latn
+    {0x9E4A0000u, 40u}, // ksh -> Latn
+    {0xA64A0000u, 40u}, // ksj -> Latn
+    {0xC64A0000u, 40u}, // ksr -> Latn
+    {0x866A0000u, 18u}, // ktb -> Ethi
+    {0xB26A0000u, 40u}, // ktm -> Latn
+    {0xBA6A0000u, 40u}, // kto -> Latn
+    {0x6B750000u, 40u}, // ku -> Latn
     {0x6B754952u,  1u}, // ku-IR -> Arab
     {0x6B754C42u,  1u}, // ku-LB -> Arab
+    {0x868A0000u, 40u}, // kub -> Latn
+    {0x8E8A0000u, 40u}, // kud -> Latn
+    {0x928A0000u, 40u}, // kue -> Latn
+    {0xA68A0000u, 40u}, // kuj -> Latn
     {0xB28A0000u, 15u}, // kum -> Cyrl
+    {0xB68A0000u, 40u}, // kun -> Latn
+    {0xBE8A0000u, 40u}, // kup -> Latn
+    {0xCA8A0000u, 40u}, // kus -> Latn
     {0x6B760000u, 15u}, // kv -> Cyrl
-    {0xC6AA0000u, 41u}, // kvr -> Latn
+    {0x9AAA0000u, 40u}, // kvg -> Latn
+    {0xC6AA0000u, 40u}, // kvr -> Latn
     {0xDEAA0000u,  1u}, // kvx -> Arab
-    {0x6B770000u, 41u}, // kw -> Latn
-    {0xB2EA0000u, 79u}, // kxm -> Thai
+    {0x6B770000u, 40u}, // kw -> Latn
+    {0xA6CA0000u, 40u}, // kwj -> Latn
+    {0xBACA0000u, 40u}, // kwo -> Latn
+    {0x82EA0000u, 40u}, // kxa -> Latn
+    {0x8AEA0000u, 18u}, // kxc -> Ethi
+    {0xB2EA0000u, 80u}, // kxm -> Thai
     {0xBEEA0000u,  1u}, // kxp -> Arab
+    {0xDAEA0000u, 40u}, // kxw -> Latn
+    {0xE6EA0000u, 40u}, // kxz -> Latn
     {0x6B790000u, 15u}, // ky -> Cyrl
     {0x6B79434Eu,  1u}, // ky-CN -> Arab
-    {0x6B795452u, 41u}, // ky-TR -> Latn
-    {0x6C610000u, 41u}, // la -> Latn
-    {0x840B0000u, 43u}, // lab -> Lina
+    {0x6B795452u, 40u}, // ky-TR -> Latn
+    {0x930A0000u, 40u}, // kye -> Latn
+    {0xDF0A0000u, 40u}, // kyx -> Latn
+    {0xC72A0000u, 40u}, // kzr -> Latn
+    {0x6C610000u, 40u}, // la -> Latn
+    {0x840B0000u, 42u}, // lab -> Lina
     {0x8C0B0000u, 27u}, // lad -> Hebr
-    {0x980B0000u, 41u}, // lag -> Latn
+    {0x980B0000u, 40u}, // lag -> Latn
     {0x9C0B0000u,  1u}, // lah -> Arab
-    {0xA40B0000u, 41u}, // laj -> Latn
-    {0x6C620000u, 41u}, // lb -> Latn
+    {0xA40B0000u, 40u}, // laj -> Latn
+    {0xC80B0000u, 40u}, // las -> Latn
+    {0x6C620000u, 40u}, // lb -> Latn
     {0x902B0000u, 15u}, // lbe -> Cyrl
-    {0xD82B0000u, 41u}, // lbw -> Latn
-    {0xBC4B0000u, 79u}, // lcp -> Thai
-    {0xBC8B0000u, 42u}, // lep -> Lepc
+    {0xD02B0000u, 40u}, // lbu -> Latn
+    {0xD82B0000u, 40u}, // lbw -> Latn
+    {0xB04B0000u, 40u}, // lcm -> Latn
+    {0xBC4B0000u, 80u}, // lcp -> Thai
+    {0x846B0000u, 40u}, // ldb -> Latn
+    {0x8C8B0000u, 40u}, // led -> Latn
+    {0x908B0000u, 40u}, // lee -> Latn
+    {0xB08B0000u, 40u}, // lem -> Latn
+    {0xBC8B0000u, 41u}, // lep -> Lepc
+    {0xC08B0000u, 40u}, // leq -> Latn
+    {0xD08B0000u, 40u}, // leu -> Latn
     {0xE48B0000u, 15u}, // lez -> Cyrl
-    {0x6C670000u, 41u}, // lg -> Latn
-    {0x6C690000u, 41u}, // li -> Latn
+    {0x6C670000u, 40u}, // lg -> Latn
+    {0x98CB0000u, 40u}, // lgg -> Latn
+    {0x6C690000u, 40u}, // li -> Latn
+    {0x810B0000u, 40u}, // lia -> Latn
+    {0x8D0B0000u, 40u}, // lid -> Latn
     {0x950B0000u, 16u}, // lif -> Deva
-    {0xA50B0000u, 41u}, // lij -> Latn
-    {0xC90B0000u, 44u}, // lis -> Lisu
-    {0xBD2B0000u, 41u}, // ljp -> Latn
+    {0x990B0000u, 40u}, // lig -> Latn
+    {0x9D0B0000u, 40u}, // lih -> Latn
+    {0xA50B0000u, 40u}, // lij -> Latn
+    {0xC90B0000u, 43u}, // lis -> Lisu
+    {0xBD2B0000u, 40u}, // ljp -> Latn
     {0xA14B0000u,  1u}, // lki -> Arab
-    {0xCD4B0000u, 41u}, // lkt -> Latn
-    {0xB58B0000u, 76u}, // lmn -> Telu
-    {0xB98B0000u, 41u}, // lmo -> Latn
-    {0x6C6E0000u, 41u}, // ln -> Latn
-    {0x6C6F0000u, 40u}, // lo -> Laoo
-    {0xADCB0000u, 41u}, // lol -> Latn
-    {0xE5CB0000u, 41u}, // loz -> Latn
+    {0xCD4B0000u, 40u}, // lkt -> Latn
+    {0x916B0000u, 40u}, // lle -> Latn
+    {0xB56B0000u, 40u}, // lln -> Latn
+    {0xB58B0000u, 77u}, // lmn -> Telu
+    {0xB98B0000u, 40u}, // lmo -> Latn
+    {0xBD8B0000u, 40u}, // lmp -> Latn
+    {0x6C6E0000u, 40u}, // ln -> Latn
+    {0xC9AB0000u, 40u}, // lns -> Latn
+    {0xD1AB0000u, 40u}, // lnu -> Latn
+    {0x6C6F0000u, 39u}, // lo -> Laoo
+    {0xA5CB0000u, 40u}, // loj -> Latn
+    {0xA9CB0000u, 40u}, // lok -> Latn
+    {0xADCB0000u, 40u}, // lol -> Latn
+    {0xC5CB0000u, 40u}, // lor -> Latn
+    {0xC9CB0000u, 40u}, // los -> Latn
+    {0xE5CB0000u, 40u}, // loz -> Latn
     {0x8A2B0000u,  1u}, // lrc -> Arab
-    {0x6C740000u, 41u}, // lt -> Latn
-    {0x9A6B0000u, 41u}, // ltg -> Latn
-    {0x6C750000u, 41u}, // lu -> Latn
-    {0x828B0000u, 41u}, // lua -> Latn
-    {0xBA8B0000u, 41u}, // luo -> Latn
-    {0xE28B0000u, 41u}, // luy -> Latn
+    {0x6C740000u, 40u}, // lt -> Latn
+    {0x9A6B0000u, 40u}, // ltg -> Latn
+    {0x6C750000u, 40u}, // lu -> Latn
+    {0x828B0000u, 40u}, // lua -> Latn
+    {0xBA8B0000u, 40u}, // luo -> Latn
+    {0xE28B0000u, 40u}, // luy -> Latn
     {0xE68B0000u,  1u}, // luz -> Arab
-    {0x6C760000u, 41u}, // lv -> Latn
-    {0xAECB0000u, 79u}, // lwl -> Thai
+    {0x6C760000u, 40u}, // lv -> Latn
+    {0xAECB0000u, 80u}, // lwl -> Thai
     {0x9F2B0000u, 24u}, // lzh -> Hans
-    {0xE72B0000u, 41u}, // lzz -> Latn
-    {0x8C0C0000u, 41u}, // mad -> Latn
-    {0x940C0000u, 41u}, // maf -> Latn
+    {0xE72B0000u, 40u}, // lzz -> Latn
+    {0x8C0C0000u, 40u}, // mad -> Latn
+    {0x940C0000u, 40u}, // maf -> Latn
     {0x980C0000u, 16u}, // mag -> Deva
     {0xA00C0000u, 16u}, // mai -> Deva
-    {0xA80C0000u, 41u}, // mak -> Latn
-    {0xB40C0000u, 41u}, // man -> Latn
-    {0xB40C474Eu, 55u}, // man-GN -> Nkoo
-    {0xC80C0000u, 41u}, // mas -> Latn
-    {0xE40C0000u, 41u}, // maz -> Latn
+    {0xA80C0000u, 40u}, // mak -> Latn
+    {0xB40C0000u, 40u}, // man -> Latn
+    {0xB40C474Eu, 54u}, // man-GN -> Nkoo
+    {0xC80C0000u, 40u}, // mas -> Latn
+    {0xD80C0000u, 40u}, // maw -> Latn
+    {0xE40C0000u, 40u}, // maz -> Latn
+    {0x9C2C0000u, 40u}, // mbh -> Latn
+    {0xB82C0000u, 40u}, // mbo -> Latn
+    {0xC02C0000u, 40u}, // mbq -> Latn
+    {0xD02C0000u, 40u}, // mbu -> Latn
+    {0xD82C0000u, 40u}, // mbw -> Latn
+    {0xA04C0000u, 40u}, // mci -> Latn
+    {0xBC4C0000u, 40u}, // mcp -> Latn
+    {0xC04C0000u, 40u}, // mcq -> Latn
+    {0xC44C0000u, 40u}, // mcr -> Latn
+    {0xD04C0000u, 40u}, // mcu -> Latn
+    {0x806C0000u, 40u}, // mda -> Latn
+    {0x906C0000u,  1u}, // mde -> Arab
     {0x946C0000u, 15u}, // mdf -> Cyrl
-    {0x9C6C0000u, 41u}, // mdh -> Latn
-    {0xC46C0000u, 41u}, // mdr -> Latn
-    {0xB48C0000u, 41u}, // men -> Latn
-    {0xC48C0000u, 41u}, // mer -> Latn
+    {0x9C6C0000u, 40u}, // mdh -> Latn
+    {0xA46C0000u, 40u}, // mdj -> Latn
+    {0xC46C0000u, 40u}, // mdr -> Latn
+    {0xDC6C0000u, 18u}, // mdx -> Ethi
+    {0x8C8C0000u, 40u}, // med -> Latn
+    {0x908C0000u, 40u}, // mee -> Latn
+    {0xA88C0000u, 40u}, // mek -> Latn
+    {0xB48C0000u, 40u}, // men -> Latn
+    {0xC48C0000u, 40u}, // mer -> Latn
+    {0xCC8C0000u, 40u}, // met -> Latn
+    {0xD08C0000u, 40u}, // meu -> Latn
     {0x80AC0000u,  1u}, // mfa -> Arab
-    {0x90AC0000u, 41u}, // mfe -> Latn
-    {0x6D670000u, 41u}, // mg -> Latn
-    {0x9CCC0000u, 41u}, // mgh -> Latn
-    {0xB8CC0000u, 41u}, // mgo -> Latn
+    {0x90AC0000u, 40u}, // mfe -> Latn
+    {0xB4AC0000u, 40u}, // mfn -> Latn
+    {0xB8AC0000u, 40u}, // mfo -> Latn
+    {0xC0AC0000u, 40u}, // mfq -> Latn
+    {0x6D670000u, 40u}, // mg -> Latn
+    {0x9CCC0000u, 40u}, // mgh -> Latn
+    {0xACCC0000u, 40u}, // mgl -> Latn
+    {0xB8CC0000u, 40u}, // mgo -> Latn
     {0xBCCC0000u, 16u}, // mgp -> Deva
-    {0xE0CC0000u, 41u}, // mgy -> Latn
-    {0x6D680000u, 41u}, // mh -> Latn
-    {0x6D690000u, 41u}, // mi -> Latn
-    {0xB50C0000u, 41u}, // min -> Latn
+    {0xE0CC0000u, 40u}, // mgy -> Latn
+    {0x6D680000u, 40u}, // mh -> Latn
+    {0xA0EC0000u, 40u}, // mhi -> Latn
+    {0xACEC0000u, 40u}, // mhl -> Latn
+    {0x6D690000u, 40u}, // mi -> Latn
+    {0x950C0000u, 40u}, // mif -> Latn
+    {0xB50C0000u, 40u}, // min -> Latn
     {0xC90C0000u, 26u}, // mis -> Hatr
+    {0xD90C0000u, 40u}, // miw -> Latn
     {0x6D6B0000u, 15u}, // mk -> Cyrl
-    {0x6D6C0000u, 50u}, // ml -> Mlym
-    {0xC96C0000u, 41u}, // mls -> Latn
+    {0xA14C0000u,  1u}, // mki -> Arab
+    {0xAD4C0000u, 40u}, // mkl -> Latn
+    {0xBD4C0000u, 40u}, // mkp -> Latn
+    {0xD94C0000u, 40u}, // mkw -> Latn
+    {0x6D6C0000u, 49u}, // ml -> Mlym
+    {0x916C0000u, 40u}, // mle -> Latn
+    {0xBD6C0000u, 40u}, // mlp -> Latn
+    {0xC96C0000u, 40u}, // mls -> Latn
+    {0xB98C0000u, 40u}, // mmo -> Latn
+    {0xD18C0000u, 40u}, // mmu -> Latn
+    {0xDD8C0000u, 40u}, // mmx -> Latn
     {0x6D6E0000u, 15u}, // mn -> Cyrl
-    {0x6D6E434Eu, 51u}, // mn-CN -> Mong
+    {0x6D6E434Eu, 50u}, // mn-CN -> Mong
+    {0x81AC0000u, 40u}, // mna -> Latn
+    {0x95AC0000u, 40u}, // mnf -> Latn
     {0xA1AC0000u,  7u}, // mni -> Beng
-    {0xD9AC0000u, 53u}, // mnw -> Mymr
-    {0x91CC0000u, 41u}, // moe -> Latn
-    {0x9DCC0000u, 41u}, // moh -> Latn
-    {0xC9CC0000u, 41u}, // mos -> Latn
+    {0xD9AC0000u, 52u}, // mnw -> Mymr
+    {0x81CC0000u, 40u}, // moa -> Latn
+    {0x91CC0000u, 40u}, // moe -> Latn
+    {0x9DCC0000u, 40u}, // moh -> Latn
+    {0xC9CC0000u, 40u}, // mos -> Latn
+    {0xDDCC0000u, 40u}, // mox -> Latn
+    {0xBDEC0000u, 40u}, // mpp -> Latn
+    {0xC9EC0000u, 40u}, // mps -> Latn
+    {0xCDEC0000u, 40u}, // mpt -> Latn
+    {0xDDEC0000u, 40u}, // mpx -> Latn
+    {0xAE0C0000u, 40u}, // mql -> Latn
     {0x6D720000u, 16u}, // mr -> Deva
     {0x8E2C0000u, 16u}, // mrd -> Deva
     {0xA62C0000u, 15u}, // mrj -> Cyrl
-    {0xD22C0000u, 52u}, // mru -> Mroo
-    {0x6D730000u, 41u}, // ms -> Latn
+    {0xBA2C0000u, 51u}, // mro -> Mroo
+    {0x6D730000u, 40u}, // ms -> Latn
     {0x6D734343u,  1u}, // ms-CC -> Arab
     {0x6D734944u,  1u}, // ms-ID -> Arab
-    {0x6D740000u, 41u}, // mt -> Latn
+    {0x6D740000u, 40u}, // mt -> Latn
+    {0x8A6C0000u, 40u}, // mtc -> Latn
+    {0x966C0000u, 40u}, // mtf -> Latn
+    {0xA26C0000u, 40u}, // mti -> Latn
     {0xC66C0000u, 16u}, // mtr -> Deva
-    {0x828C0000u, 41u}, // mua -> Latn
-    {0xCA8C0000u, 41u}, // mus -> Latn
+    {0x828C0000u, 40u}, // mua -> Latn
+    {0xC68C0000u, 40u}, // mur -> Latn
+    {0xCA8C0000u, 40u}, // mus -> Latn
+    {0x82AC0000u, 40u}, // mva -> Latn
+    {0xB6AC0000u, 40u}, // mvn -> Latn
     {0xE2AC0000u,  1u}, // mvy -> Arab
-    {0xAACC0000u, 41u}, // mwk -> Latn
+    {0xAACC0000u, 40u}, // mwk -> Latn
     {0xC6CC0000u, 16u}, // mwr -> Deva
-    {0xD6CC0000u, 41u}, // mwv -> Latn
-    {0x8AEC0000u, 41u}, // mxc -> Latn
-    {0x6D790000u, 53u}, // my -> Mymr
+    {0xD6CC0000u, 40u}, // mwv -> Latn
+    {0x8AEC0000u, 40u}, // mxc -> Latn
+    {0xB2EC0000u, 40u}, // mxm -> Latn
+    {0x6D790000u, 52u}, // my -> Mymr
+    {0xAB0C0000u, 40u}, // myk -> Latn
+    {0xB30C0000u, 18u}, // mym -> Ethi
     {0xD70C0000u, 15u}, // myv -> Cyrl
-    {0xDF0C0000u, 41u}, // myx -> Latn
-    {0xE70C0000u, 47u}, // myz -> Mand
+    {0xDB0C0000u, 40u}, // myw -> Latn
+    {0xDF0C0000u, 40u}, // myx -> Latn
+    {0xE70C0000u, 46u}, // myz -> Mand
+    {0xAB2C0000u, 40u}, // mzk -> Latn
+    {0xB32C0000u, 40u}, // mzm -> Latn
     {0xB72C0000u,  1u}, // mzn -> Arab
-    {0x6E610000u, 41u}, // na -> Latn
+    {0xBF2C0000u, 40u}, // mzp -> Latn
+    {0xDB2C0000u, 40u}, // mzw -> Latn
+    {0xE72C0000u, 40u}, // mzz -> Latn
+    {0x6E610000u, 40u}, // na -> Latn
+    {0x880D0000u, 40u}, // nac -> Latn
+    {0x940D0000u, 40u}, // naf -> Latn
+    {0xA80D0000u, 40u}, // nak -> Latn
     {0xB40D0000u, 24u}, // nan -> Hans
-    {0xBC0D0000u, 41u}, // nap -> Latn
-    {0xC00D0000u, 41u}, // naq -> Latn
-    {0x6E620000u, 41u}, // nb -> Latn
-    {0x9C4D0000u, 41u}, // nch -> Latn
-    {0x6E640000u, 41u}, // nd -> Latn
-    {0x886D0000u, 41u}, // ndc -> Latn
-    {0xC86D0000u, 41u}, // nds -> Latn
+    {0xBC0D0000u, 40u}, // nap -> Latn
+    {0xC00D0000u, 40u}, // naq -> Latn
+    {0xC80D0000u, 40u}, // nas -> Latn
+    {0x6E620000u, 40u}, // nb -> Latn
+    {0x804D0000u, 40u}, // nca -> Latn
+    {0x904D0000u, 40u}, // nce -> Latn
+    {0x944D0000u, 40u}, // ncf -> Latn
+    {0x9C4D0000u, 40u}, // nch -> Latn
+    {0xB84D0000u, 40u}, // nco -> Latn
+    {0xD04D0000u, 40u}, // ncu -> Latn
+    {0x6E640000u, 40u}, // nd -> Latn
+    {0x886D0000u, 40u}, // ndc -> Latn
+    {0xC86D0000u, 40u}, // nds -> Latn
     {0x6E650000u, 16u}, // ne -> Deva
+    {0x848D0000u, 40u}, // neb -> Latn
     {0xD88D0000u, 16u}, // new -> Deva
-    {0x6E670000u, 41u}, // ng -> Latn
-    {0xACCD0000u, 41u}, // ngl -> Latn
-    {0x90ED0000u, 41u}, // nhe -> Latn
-    {0xD8ED0000u, 41u}, // nhw -> Latn
-    {0xA50D0000u, 41u}, // nij -> Latn
-    {0xD10D0000u, 41u}, // niu -> Latn
-    {0xB92D0000u, 41u}, // njo -> Latn
-    {0x6E6C0000u, 41u}, // nl -> Latn
-    {0x998D0000u, 41u}, // nmg -> Latn
-    {0x6E6E0000u, 41u}, // nn -> Latn
-    {0x9DAD0000u, 41u}, // nnh -> Latn
-    {0x6E6F0000u, 41u}, // no -> Latn
-    {0x8DCD0000u, 39u}, // nod -> Lana
+    {0xDC8D0000u, 40u}, // nex -> Latn
+    {0xC4AD0000u, 40u}, // nfr -> Latn
+    {0x6E670000u, 40u}, // ng -> Latn
+    {0x80CD0000u, 40u}, // nga -> Latn
+    {0x84CD0000u, 40u}, // ngb -> Latn
+    {0xACCD0000u, 40u}, // ngl -> Latn
+    {0x84ED0000u, 40u}, // nhb -> Latn
+    {0x90ED0000u, 40u}, // nhe -> Latn
+    {0xD8ED0000u, 40u}, // nhw -> Latn
+    {0x950D0000u, 40u}, // nif -> Latn
+    {0xA10D0000u, 40u}, // nii -> Latn
+    {0xA50D0000u, 40u}, // nij -> Latn
+    {0xB50D0000u, 40u}, // nin -> Latn
+    {0xD10D0000u, 40u}, // niu -> Latn
+    {0xE10D0000u, 40u}, // niy -> Latn
+    {0xE50D0000u, 40u}, // niz -> Latn
+    {0xB92D0000u, 40u}, // njo -> Latn
+    {0x994D0000u, 40u}, // nkg -> Latn
+    {0xB94D0000u, 40u}, // nko -> Latn
+    {0x6E6C0000u, 40u}, // nl -> Latn
+    {0x998D0000u, 40u}, // nmg -> Latn
+    {0xE58D0000u, 40u}, // nmz -> Latn
+    {0x6E6E0000u, 40u}, // nn -> Latn
+    {0x95AD0000u, 40u}, // nnf -> Latn
+    {0x9DAD0000u, 40u}, // nnh -> Latn
+    {0xA9AD0000u, 40u}, // nnk -> Latn
+    {0xB1AD0000u, 40u}, // nnm -> Latn
+    {0x6E6F0000u, 40u}, // no -> Latn
+    {0x8DCD0000u, 38u}, // nod -> Lana
     {0x91CD0000u, 16u}, // noe -> Deva
     {0xB5CD0000u, 64u}, // non -> Runr
-    {0xBA0D0000u, 55u}, // nqo -> Nkoo
-    {0x6E720000u, 41u}, // nr -> Latn
+    {0xBDCD0000u, 40u}, // nop -> Latn
+    {0xD1CD0000u, 40u}, // nou -> Latn
+    {0xBA0D0000u, 54u}, // nqo -> Nkoo
+    {0x6E720000u, 40u}, // nr -> Latn
+    {0x862D0000u, 40u}, // nrb -> Latn
     {0xAA4D0000u,  9u}, // nsk -> Cans
-    {0xBA4D0000u, 41u}, // nso -> Latn
-    {0xCA8D0000u, 41u}, // nus -> Latn
-    {0x6E760000u, 41u}, // nv -> Latn
-    {0xC2ED0000u, 41u}, // nxq -> Latn
-    {0x6E790000u, 41u}, // ny -> Latn
-    {0xB30D0000u, 41u}, // nym -> Latn
-    {0xB70D0000u, 41u}, // nyn -> Latn
-    {0xA32D0000u, 41u}, // nzi -> Latn
-    {0x6F630000u, 41u}, // oc -> Latn
-    {0x6F6D0000u, 41u}, // om -> Latn
-    {0x6F720000u, 58u}, // or -> Orya
+    {0xB64D0000u, 40u}, // nsn -> Latn
+    {0xBA4D0000u, 40u}, // nso -> Latn
+    {0xCA4D0000u, 40u}, // nss -> Latn
+    {0xB26D0000u, 40u}, // ntm -> Latn
+    {0xC66D0000u, 40u}, // ntr -> Latn
+    {0xA28D0000u, 40u}, // nui -> Latn
+    {0xBE8D0000u, 40u}, // nup -> Latn
+    {0xCA8D0000u, 40u}, // nus -> Latn
+    {0xD68D0000u, 40u}, // nuv -> Latn
+    {0xDE8D0000u, 40u}, // nux -> Latn
+    {0x6E760000u, 40u}, // nv -> Latn
+    {0x86CD0000u, 40u}, // nwb -> Latn
+    {0xC2ED0000u, 40u}, // nxq -> Latn
+    {0xC6ED0000u, 40u}, // nxr -> Latn
+    {0x6E790000u, 40u}, // ny -> Latn
+    {0xB30D0000u, 40u}, // nym -> Latn
+    {0xB70D0000u, 40u}, // nyn -> Latn
+    {0xA32D0000u, 40u}, // nzi -> Latn
+    {0x6F630000u, 40u}, // oc -> Latn
+    {0x88CE0000u, 40u}, // ogc -> Latn
+    {0xC54E0000u, 40u}, // okr -> Latn
+    {0xD54E0000u, 40u}, // okv -> Latn
+    {0x6F6D0000u, 40u}, // om -> Latn
+    {0x99AE0000u, 40u}, // ong -> Latn
+    {0xB5AE0000u, 40u}, // onn -> Latn
+    {0xC9AE0000u, 40u}, // ons -> Latn
+    {0xB1EE0000u, 40u}, // opm -> Latn
+    {0x6F720000u, 57u}, // or -> Orya
+    {0xBA2E0000u, 40u}, // oro -> Latn
+    {0xD22E0000u,  1u}, // oru -> Arab
     {0x6F730000u, 15u}, // os -> Cyrl
-    {0xAA6E0000u, 57u}, // otk -> Orkh
+    {0x824E0000u, 58u}, // osa -> Osge
+    {0x826E0000u,  1u}, // ota -> Arab
+    {0xAA6E0000u, 56u}, // otk -> Orkh
+    {0xB32E0000u, 40u}, // ozm -> Latn
     {0x70610000u, 23u}, // pa -> Guru
     {0x7061504Bu,  1u}, // pa-PK -> Arab
-    {0x980F0000u, 41u}, // pag -> Latn
+    {0x980F0000u, 40u}, // pag -> Latn
     {0xAC0F0000u, 60u}, // pal -> Phli
-    {0xB00F0000u, 41u}, // pam -> Latn
-    {0xBC0F0000u, 41u}, // pap -> Latn
-    {0xD00F0000u, 41u}, // pau -> Latn
-    {0x8C4F0000u, 41u}, // pcd -> Latn
-    {0xB04F0000u, 41u}, // pcm -> Latn
-    {0x886F0000u, 41u}, // pdc -> Latn
-    {0xCC6F0000u, 41u}, // pdt -> Latn
-    {0xB88F0000u, 83u}, // peo -> Xpeo
-    {0xACAF0000u, 41u}, // pfl -> Latn
+    {0xB00F0000u, 40u}, // pam -> Latn
+    {0xBC0F0000u, 40u}, // pap -> Latn
+    {0xD00F0000u, 40u}, // pau -> Latn
+    {0xA02F0000u, 40u}, // pbi -> Latn
+    {0x8C4F0000u, 40u}, // pcd -> Latn
+    {0xB04F0000u, 40u}, // pcm -> Latn
+    {0x886F0000u, 40u}, // pdc -> Latn
+    {0xCC6F0000u, 40u}, // pdt -> Latn
+    {0x8C8F0000u, 40u}, // ped -> Latn
+    {0xB88F0000u, 84u}, // peo -> Xpeo
+    {0xDC8F0000u, 40u}, // pex -> Latn
+    {0xACAF0000u, 40u}, // pfl -> Latn
+    {0xACEF0000u,  1u}, // phl -> Arab
     {0xB4EF0000u, 61u}, // phn -> Phnx
+    {0xAD0F0000u, 40u}, // pil -> Latn
+    {0xBD0F0000u, 40u}, // pip -> Latn
     {0x814F0000u,  8u}, // pka -> Brah
-    {0xB94F0000u, 41u}, // pko -> Latn
-    {0x706C0000u, 41u}, // pl -> Latn
-    {0xC98F0000u, 41u}, // pms -> Latn
+    {0xB94F0000u, 40u}, // pko -> Latn
+    {0x706C0000u, 40u}, // pl -> Latn
+    {0x816F0000u, 40u}, // pla -> Latn
+    {0xC98F0000u, 40u}, // pms -> Latn
+    {0x99AF0000u, 40u}, // png -> Latn
+    {0xB5AF0000u, 40u}, // pnn -> Latn
     {0xCDAF0000u, 21u}, // pnt -> Grek
-    {0xB5CF0000u, 41u}, // pon -> Latn
+    {0xB5CF0000u, 40u}, // pon -> Latn
+    {0xB9EF0000u, 40u}, // ppo -> Latn
     {0x822F0000u, 34u}, // pra -> Khar
     {0x8E2F0000u,  1u}, // prd -> Arab
-    {0x9A2F0000u, 41u}, // prg -> Latn
+    {0x9A2F0000u, 40u}, // prg -> Latn
     {0x70730000u,  1u}, // ps -> Arab
-    {0x70740000u, 41u}, // pt -> Latn
-    {0xD28F0000u, 41u}, // puu -> Latn
-    {0x71750000u, 41u}, // qu -> Latn
-    {0x8A900000u, 41u}, // quc -> Latn
-    {0x9A900000u, 41u}, // qug -> Latn
+    {0xCA4F0000u, 40u}, // pss -> Latn
+    {0x70740000u, 40u}, // pt -> Latn
+    {0xBE6F0000u, 40u}, // ptp -> Latn
+    {0xD28F0000u, 40u}, // puu -> Latn
+    {0x82CF0000u, 40u}, // pwa -> Latn
+    {0x71750000u, 40u}, // qu -> Latn
+    {0x8A900000u, 40u}, // quc -> Latn
+    {0x9A900000u, 40u}, // qug -> Latn
+    {0xA0110000u, 40u}, // rai -> Latn
     {0xA4110000u, 16u}, // raj -> Deva
-    {0x94510000u, 41u}, // rcf -> Latn
-    {0xA4910000u, 41u}, // rej -> Latn
-    {0xB4D10000u, 41u}, // rgn -> Latn
-    {0x81110000u, 41u}, // ria -> Latn
-    {0x95110000u, 77u}, // rif -> Tfng
-    {0x95114E4Cu, 41u}, // rif-NL -> Latn
+    {0xB8110000u, 40u}, // rao -> Latn
+    {0x94510000u, 40u}, // rcf -> Latn
+    {0xA4910000u, 40u}, // rej -> Latn
+    {0xAC910000u, 40u}, // rel -> Latn
+    {0xC8910000u, 40u}, // res -> Latn
+    {0xB4D10000u, 40u}, // rgn -> Latn
+    {0x98F10000u,  1u}, // rhg -> Arab
+    {0x81110000u, 40u}, // ria -> Latn
+    {0x95110000u, 78u}, // rif -> Tfng
+    {0x95114E4Cu, 40u}, // rif-NL -> Latn
     {0xC9310000u, 16u}, // rjs -> Deva
     {0xCD510000u,  7u}, // rkt -> Beng
-    {0x726D0000u, 41u}, // rm -> Latn
-    {0x95910000u, 41u}, // rmf -> Latn
-    {0xB9910000u, 41u}, // rmo -> Latn
+    {0x726D0000u, 40u}, // rm -> Latn
+    {0x95910000u, 40u}, // rmf -> Latn
+    {0xB9910000u, 40u}, // rmo -> Latn
     {0xCD910000u,  1u}, // rmt -> Arab
-    {0xD1910000u, 41u}, // rmu -> Latn
-    {0x726E0000u, 41u}, // rn -> Latn
-    {0x99B10000u, 41u}, // rng -> Latn
-    {0x726F0000u, 41u}, // ro -> Latn
-    {0x85D10000u, 41u}, // rob -> Latn
-    {0x95D10000u, 41u}, // rof -> Latn
-    {0xB2710000u, 41u}, // rtm -> Latn
+    {0xD1910000u, 40u}, // rmu -> Latn
+    {0x726E0000u, 40u}, // rn -> Latn
+    {0x81B10000u, 40u}, // rna -> Latn
+    {0x99B10000u, 40u}, // rng -> Latn
+    {0x726F0000u, 40u}, // ro -> Latn
+    {0x85D10000u, 40u}, // rob -> Latn
+    {0x95D10000u, 40u}, // rof -> Latn
+    {0xB9D10000u, 40u}, // roo -> Latn
+    {0xBA310000u, 40u}, // rro -> Latn
+    {0xB2710000u, 40u}, // rtm -> Latn
     {0x72750000u, 15u}, // ru -> Cyrl
     {0x92910000u, 15u}, // rue -> Cyrl
-    {0x9A910000u, 41u}, // rug -> Latn
-    {0x72770000u, 41u}, // rw -> Latn
-    {0xAAD10000u, 41u}, // rwk -> Latn
+    {0x9A910000u, 40u}, // rug -> Latn
+    {0x72770000u, 40u}, // rw -> Latn
+    {0xAAD10000u, 40u}, // rwk -> Latn
+    {0xBAD10000u, 40u}, // rwo -> Latn
     {0xD3110000u, 33u}, // ryu -> Kana
     {0x73610000u, 16u}, // sa -> Deva
-    {0x94120000u, 41u}, // saf -> Latn
+    {0x94120000u, 40u}, // saf -> Latn
     {0x9C120000u, 15u}, // sah -> Cyrl
-    {0xC0120000u, 41u}, // saq -> Latn
-    {0xC8120000u, 41u}, // sas -> Latn
-    {0xCC120000u, 41u}, // sat -> Latn
+    {0xC0120000u, 40u}, // saq -> Latn
+    {0xC8120000u, 40u}, // sas -> Latn
+    {0xCC120000u, 40u}, // sat -> Latn
     {0xE4120000u, 67u}, // saz -> Saur
-    {0xBC320000u, 41u}, // sbp -> Latn
-    {0x73630000u, 41u}, // sc -> Latn
+    {0x80320000u, 40u}, // sba -> Latn
+    {0x90320000u, 40u}, // sbe -> Latn
+    {0xBC320000u, 40u}, // sbp -> Latn
+    {0x73630000u, 40u}, // sc -> Latn
     {0xA8520000u, 16u}, // sck -> Deva
-    {0xB4520000u, 41u}, // scn -> Latn
-    {0xB8520000u, 41u}, // sco -> Latn
-    {0xC8520000u, 41u}, // scs -> Latn
+    {0xAC520000u,  1u}, // scl -> Arab
+    {0xB4520000u, 40u}, // scn -> Latn
+    {0xB8520000u, 40u}, // sco -> Latn
+    {0xC8520000u, 40u}, // scs -> Latn
     {0x73640000u,  1u}, // sd -> Arab
-    {0x88720000u, 41u}, // sdc -> Latn
+    {0x88720000u, 40u}, // sdc -> Latn
     {0x9C720000u,  1u}, // sdh -> Arab
-    {0x73650000u, 41u}, // se -> Latn
-    {0x94920000u, 41u}, // sef -> Latn
-    {0x9C920000u, 41u}, // seh -> Latn
-    {0xA0920000u, 41u}, // sei -> Latn
-    {0xC8920000u, 41u}, // ses -> Latn
-    {0x73670000u, 41u}, // sg -> Latn
-    {0x80D20000u, 56u}, // sga -> Ogam
-    {0xC8D20000u, 41u}, // sgs -> Latn
-    {0x73680000u, 41u}, // sh -> Latn
-    {0xA0F20000u, 77u}, // shi -> Tfng
-    {0xB4F20000u, 53u}, // shn -> Mymr
+    {0x73650000u, 40u}, // se -> Latn
+    {0x94920000u, 40u}, // sef -> Latn
+    {0x9C920000u, 40u}, // seh -> Latn
+    {0xA0920000u, 40u}, // sei -> Latn
+    {0xC8920000u, 40u}, // ses -> Latn
+    {0x73670000u, 40u}, // sg -> Latn
+    {0x80D20000u, 55u}, // sga -> Ogam
+    {0xC8D20000u, 40u}, // sgs -> Latn
+    {0xD8D20000u, 18u}, // sgw -> Ethi
+    {0xE4D20000u, 40u}, // sgz -> Latn
+    {0x73680000u, 40u}, // sh -> Latn
+    {0xA0F20000u, 78u}, // shi -> Tfng
+    {0xA8F20000u, 40u}, // shk -> Latn
+    {0xB4F20000u, 52u}, // shn -> Mymr
+    {0xD0F20000u,  1u}, // shu -> Arab
     {0x73690000u, 69u}, // si -> Sinh
-    {0x8D120000u, 41u}, // sid -> Latn
-    {0x736B0000u, 41u}, // sk -> Latn
+    {0x8D120000u, 40u}, // sid -> Latn
+    {0x99120000u, 40u}, // sig -> Latn
+    {0xAD120000u, 40u}, // sil -> Latn
+    {0xB1120000u, 40u}, // sim -> Latn
+    {0xC5320000u, 40u}, // sjr -> Latn
+    {0x736B0000u, 40u}, // sk -> Latn
+    {0x89520000u, 40u}, // skc -> Latn
     {0xC5520000u,  1u}, // skr -> Arab
-    {0x736C0000u, 41u}, // sl -> Latn
-    {0xA1720000u, 41u}, // sli -> Latn
-    {0xE1720000u, 41u}, // sly -> Latn
-    {0x736D0000u, 41u}, // sm -> Latn
-    {0x81920000u, 41u}, // sma -> Latn
-    {0xA5920000u, 41u}, // smj -> Latn
-    {0xB5920000u, 41u}, // smn -> Latn
+    {0xC9520000u, 40u}, // sks -> Latn
+    {0x736C0000u, 40u}, // sl -> Latn
+    {0x8D720000u, 40u}, // sld -> Latn
+    {0xA1720000u, 40u}, // sli -> Latn
+    {0xAD720000u, 40u}, // sll -> Latn
+    {0xE1720000u, 40u}, // sly -> Latn
+    {0x736D0000u, 40u}, // sm -> Latn
+    {0x81920000u, 40u}, // sma -> Latn
+    {0xA5920000u, 40u}, // smj -> Latn
+    {0xB5920000u, 40u}, // smn -> Latn
     {0xBD920000u, 65u}, // smp -> Samr
-    {0xC9920000u, 41u}, // sms -> Latn
-    {0x736E0000u, 41u}, // sn -> Latn
-    {0xA9B20000u, 41u}, // snk -> Latn
-    {0x736F0000u, 41u}, // so -> Latn
-    {0xD1D20000u, 79u}, // sou -> Thai
-    {0x73710000u, 41u}, // sq -> Latn
+    {0xC1920000u, 40u}, // smq -> Latn
+    {0xC9920000u, 40u}, // sms -> Latn
+    {0x736E0000u, 40u}, // sn -> Latn
+    {0x89B20000u, 40u}, // snc -> Latn
+    {0xA9B20000u, 40u}, // snk -> Latn
+    {0xBDB20000u, 40u}, // snp -> Latn
+    {0xDDB20000u, 40u}, // snx -> Latn
+    {0xE1B20000u, 40u}, // sny -> Latn
+    {0x736F0000u, 40u}, // so -> Latn
+    {0xA9D20000u, 40u}, // sok -> Latn
+    {0xC1D20000u, 40u}, // soq -> Latn
+    {0xD1D20000u, 80u}, // sou -> Thai
+    {0xE1D20000u, 40u}, // soy -> Latn
+    {0x8DF20000u, 40u}, // spd -> Latn
+    {0xADF20000u, 40u}, // spl -> Latn
+    {0xC9F20000u, 40u}, // sps -> Latn
+    {0x73710000u, 40u}, // sq -> Latn
     {0x73720000u, 15u}, // sr -> Cyrl
-    {0x73724D45u, 41u}, // sr-ME -> Latn
-    {0x7372524Fu, 41u}, // sr-RO -> Latn
-    {0x73725255u, 41u}, // sr-RU -> Latn
-    {0x73725452u, 41u}, // sr-TR -> Latn
+    {0x73724D45u, 40u}, // sr-ME -> Latn
+    {0x7372524Fu, 40u}, // sr-RO -> Latn
+    {0x73725255u, 40u}, // sr-RU -> Latn
+    {0x73725452u, 40u}, // sr-TR -> Latn
     {0x86320000u, 70u}, // srb -> Sora
-    {0xB6320000u, 41u}, // srn -> Latn
-    {0xC6320000u, 41u}, // srr -> Latn
+    {0xB6320000u, 40u}, // srn -> Latn
+    {0xC6320000u, 40u}, // srr -> Latn
     {0xDE320000u, 16u}, // srx -> Deva
-    {0x73730000u, 41u}, // ss -> Latn
-    {0xE2520000u, 41u}, // ssy -> Latn
-    {0x73740000u, 41u}, // st -> Latn
-    {0xC2720000u, 41u}, // stq -> Latn
-    {0x73750000u, 41u}, // su -> Latn
-    {0xAA920000u, 41u}, // suk -> Latn
-    {0xCA920000u, 41u}, // sus -> Latn
-    {0x73760000u, 41u}, // sv -> Latn
-    {0x73770000u, 41u}, // sw -> Latn
+    {0x73730000u, 40u}, // ss -> Latn
+    {0x8E520000u, 40u}, // ssd -> Latn
+    {0x9A520000u, 40u}, // ssg -> Latn
+    {0xE2520000u, 40u}, // ssy -> Latn
+    {0x73740000u, 40u}, // st -> Latn
+    {0xAA720000u, 40u}, // stk -> Latn
+    {0xC2720000u, 40u}, // stq -> Latn
+    {0x73750000u, 40u}, // su -> Latn
+    {0x82920000u, 40u}, // sua -> Latn
+    {0x92920000u, 40u}, // sue -> Latn
+    {0xAA920000u, 40u}, // suk -> Latn
+    {0xC6920000u, 40u}, // sur -> Latn
+    {0xCA920000u, 40u}, // sus -> Latn
+    {0x73760000u, 40u}, // sv -> Latn
+    {0x73770000u, 40u}, // sw -> Latn
     {0x86D20000u,  1u}, // swb -> Arab
-    {0x8AD20000u, 41u}, // swc -> Latn
-    {0x9AD20000u, 41u}, // swg -> Latn
+    {0x8AD20000u, 40u}, // swc -> Latn
+    {0x9AD20000u, 40u}, // swg -> Latn
+    {0xBED20000u, 40u}, // swp -> Latn
     {0xD6D20000u, 16u}, // swv -> Deva
-    {0xB6F20000u, 41u}, // sxn -> Latn
+    {0xB6F20000u, 40u}, // sxn -> Latn
+    {0xDAF20000u, 40u}, // sxw -> Latn
     {0xAF120000u,  7u}, // syl -> Beng
     {0xC7120000u, 71u}, // syr -> Syrc
-    {0xAF320000u, 41u}, // szl -> Latn
+    {0xAF320000u, 40u}, // szl -> Latn
     {0x74610000u, 74u}, // ta -> Taml
     {0xA4130000u, 16u}, // taj -> Deva
-    {0xD8330000u, 41u}, // tbw -> Latn
+    {0xAC130000u, 40u}, // tal -> Latn
+    {0xB4130000u, 40u}, // tan -> Latn
+    {0xC0130000u, 40u}, // taq -> Latn
+    {0x88330000u, 40u}, // tbc -> Latn
+    {0x8C330000u, 40u}, // tbd -> Latn
+    {0x94330000u, 40u}, // tbf -> Latn
+    {0x98330000u, 40u}, // tbg -> Latn
+    {0xB8330000u, 40u}, // tbo -> Latn
+    {0xD8330000u, 40u}, // tbw -> Latn
+    {0xE4330000u, 40u}, // tbz -> Latn
+    {0xA0530000u, 40u}, // tci -> Latn
     {0xE0530000u, 36u}, // tcy -> Knda
     {0x8C730000u, 72u}, // tdd -> Tale
     {0x98730000u, 16u}, // tdg -> Deva
     {0x9C730000u, 16u}, // tdh -> Deva
-    {0x74650000u, 76u}, // te -> Telu
-    {0xB0930000u, 41u}, // tem -> Latn
-    {0xB8930000u, 41u}, // teo -> Latn
-    {0xCC930000u, 41u}, // tet -> Latn
+    {0x74650000u, 77u}, // te -> Telu
+    {0x8C930000u, 40u}, // ted -> Latn
+    {0xB0930000u, 40u}, // tem -> Latn
+    {0xB8930000u, 40u}, // teo -> Latn
+    {0xCC930000u, 40u}, // tet -> Latn
+    {0xA0B30000u, 40u}, // tfi -> Latn
     {0x74670000u, 15u}, // tg -> Cyrl
     {0x7467504Bu,  1u}, // tg-PK -> Arab
-    {0x74680000u, 79u}, // th -> Thai
+    {0x88D30000u, 40u}, // tgc -> Latn
+    {0xB8D30000u, 40u}, // tgo -> Latn
+    {0xD0D30000u, 40u}, // tgu -> Latn
+    {0x74680000u, 80u}, // th -> Thai
     {0xACF30000u, 16u}, // thl -> Deva
     {0xC0F30000u, 16u}, // thq -> Deva
     {0xC4F30000u, 16u}, // thr -> Deva
     {0x74690000u, 18u}, // ti -> Ethi
+    {0x95130000u, 40u}, // tif -> Latn
     {0x99130000u, 18u}, // tig -> Ethi
-    {0xD5130000u, 41u}, // tiv -> Latn
-    {0x746B0000u, 41u}, // tk -> Latn
-    {0xAD530000u, 41u}, // tkl -> Latn
-    {0xC5530000u, 41u}, // tkr -> Latn
+    {0xA9130000u, 40u}, // tik -> Latn
+    {0xB1130000u, 40u}, // tim -> Latn
+    {0xB9130000u, 40u}, // tio -> Latn
+    {0xD5130000u, 40u}, // tiv -> Latn
+    {0x746B0000u, 40u}, // tk -> Latn
+    {0xAD530000u, 40u}, // tkl -> Latn
+    {0xC5530000u, 40u}, // tkr -> Latn
     {0xCD530000u, 16u}, // tkt -> Deva
-    {0x746C0000u, 41u}, // tl -> Latn
-    {0xE1730000u, 41u}, // tly -> Latn
-    {0x9D930000u, 41u}, // tmh -> Latn
-    {0x746E0000u, 41u}, // tn -> Latn
-    {0x746F0000u, 41u}, // to -> Latn
-    {0x99D30000u, 41u}, // tog -> Latn
-    {0xA1F30000u, 41u}, // tpi -> Latn
-    {0x74720000u, 41u}, // tr -> Latn
-    {0xD2330000u, 41u}, // tru -> Latn
-    {0xD6330000u, 41u}, // trv -> Latn
-    {0x74730000u, 41u}, // ts -> Latn
+    {0x746C0000u, 40u}, // tl -> Latn
+    {0x95730000u, 40u}, // tlf -> Latn
+    {0xDD730000u, 40u}, // tlx -> Latn
+    {0xE1730000u, 40u}, // tly -> Latn
+    {0x9D930000u, 40u}, // tmh -> Latn
+    {0xE1930000u, 40u}, // tmy -> Latn
+    {0x746E0000u, 40u}, // tn -> Latn
+    {0x9DB30000u, 40u}, // tnh -> Latn
+    {0x746F0000u, 40u}, // to -> Latn
+    {0x95D30000u, 40u}, // tof -> Latn
+    {0x99D30000u, 40u}, // tog -> Latn
+    {0xC1D30000u, 40u}, // toq -> Latn
+    {0xA1F30000u, 40u}, // tpi -> Latn
+    {0xB1F30000u, 40u}, // tpm -> Latn
+    {0xE5F30000u, 40u}, // tpz -> Latn
+    {0xBA130000u, 40u}, // tqo -> Latn
+    {0x74720000u, 40u}, // tr -> Latn
+    {0xD2330000u, 40u}, // tru -> Latn
+    {0xD6330000u, 40u}, // trv -> Latn
+    {0xDA330000u,  1u}, // trw -> Arab
+    {0x74730000u, 40u}, // ts -> Latn
     {0x8E530000u, 21u}, // tsd -> Grek
     {0x96530000u, 16u}, // tsf -> Deva
-    {0x9A530000u, 41u}, // tsg -> Latn
-    {0xA6530000u, 80u}, // tsj -> Tibt
+    {0x9A530000u, 40u}, // tsg -> Latn
+    {0xA6530000u, 81u}, // tsj -> Tibt
+    {0xDA530000u, 40u}, // tsw -> Latn
     {0x74740000u, 15u}, // tt -> Cyrl
-    {0xA6730000u, 41u}, // ttj -> Latn
-    {0xCA730000u, 79u}, // tts -> Thai
-    {0xCE730000u, 41u}, // ttt -> Latn
-    {0xB2930000u, 41u}, // tum -> Latn
-    {0xAEB30000u, 41u}, // tvl -> Latn
-    {0xC2D30000u, 41u}, // twq -> Latn
-    {0x74790000u, 41u}, // ty -> Latn
+    {0x8E730000u, 40u}, // ttd -> Latn
+    {0x92730000u, 40u}, // tte -> Latn
+    {0xA6730000u, 40u}, // ttj -> Latn
+    {0xC6730000u, 40u}, // ttr -> Latn
+    {0xCA730000u, 80u}, // tts -> Thai
+    {0xCE730000u, 40u}, // ttt -> Latn
+    {0x9E930000u, 40u}, // tuh -> Latn
+    {0xAE930000u, 40u}, // tul -> Latn
+    {0xB2930000u, 40u}, // tum -> Latn
+    {0xC2930000u, 40u}, // tuq -> Latn
+    {0x8EB30000u, 40u}, // tvd -> Latn
+    {0xAEB30000u, 40u}, // tvl -> Latn
+    {0xD2B30000u, 40u}, // tvu -> Latn
+    {0x9ED30000u, 40u}, // twh -> Latn
+    {0xC2D30000u, 40u}, // twq -> Latn
+    {0x9AF30000u, 75u}, // txg -> Tang
+    {0x74790000u, 40u}, // ty -> Latn
+    {0x83130000u, 40u}, // tya -> Latn
     {0xD7130000u, 15u}, // tyv -> Cyrl
-    {0xB3330000u, 41u}, // tzm -> Latn
+    {0xB3330000u, 40u}, // tzm -> Latn
+    {0xD0340000u, 40u}, // ubu -> Latn
     {0xB0740000u, 15u}, // udm -> Cyrl
     {0x75670000u,  1u}, // ug -> Arab
     {0x75674B5Au, 15u}, // ug-KZ -> Cyrl
     {0x75674D4Eu, 15u}, // ug-MN -> Cyrl
-    {0x80D40000u, 81u}, // uga -> Ugar
+    {0x80D40000u, 82u}, // uga -> Ugar
     {0x756B0000u, 15u}, // uk -> Cyrl
-    {0xA1740000u, 41u}, // uli -> Latn
-    {0x85940000u, 41u}, // umb -> Latn
+    {0xA1740000u, 40u}, // uli -> Latn
+    {0x85940000u, 40u}, // umb -> Latn
     {0xC5B40000u,  7u}, // unr -> Beng
     {0xC5B44E50u, 16u}, // unr-NP -> Deva
     {0xDDB40000u,  7u}, // unx -> Beng
     {0x75720000u,  1u}, // ur -> Arab
-    {0x757A0000u, 41u}, // uz -> Latn
+    {0xA2340000u, 40u}, // uri -> Latn
+    {0xCE340000u, 40u}, // urt -> Latn
+    {0xDA340000u, 40u}, // urw -> Latn
+    {0x82540000u, 40u}, // usa -> Latn
+    {0xC6740000u, 40u}, // utr -> Latn
+    {0x9EB40000u, 40u}, // uvh -> Latn
+    {0xAEB40000u, 40u}, // uvl -> Latn
+    {0x757A0000u, 40u}, // uz -> Latn
     {0x757A4146u,  1u}, // uz-AF -> Arab
     {0x757A434Eu, 15u}, // uz-CN -> Cyrl
-    {0xA0150000u, 82u}, // vai -> Vaii
-    {0x76650000u, 41u}, // ve -> Latn
-    {0x88950000u, 41u}, // vec -> Latn
-    {0xBC950000u, 41u}, // vep -> Latn
-    {0x76690000u, 41u}, // vi -> Latn
-    {0x89150000u, 41u}, // vic -> Latn
-    {0xC9750000u, 41u}, // vls -> Latn
-    {0x95950000u, 41u}, // vmf -> Latn
-    {0xD9950000u, 41u}, // vmw -> Latn
-    {0x766F0000u, 41u}, // vo -> Latn
-    {0xCDD50000u, 41u}, // vot -> Latn
-    {0xBA350000u, 41u}, // vro -> Latn
-    {0xB6950000u, 41u}, // vun -> Latn
-    {0x77610000u, 41u}, // wa -> Latn
-    {0x90160000u, 41u}, // wae -> Latn
+    {0x98150000u, 40u}, // vag -> Latn
+    {0xA0150000u, 83u}, // vai -> Vaii
+    {0xB4150000u, 40u}, // van -> Latn
+    {0x76650000u, 40u}, // ve -> Latn
+    {0x88950000u, 40u}, // vec -> Latn
+    {0xBC950000u, 40u}, // vep -> Latn
+    {0x76690000u, 40u}, // vi -> Latn
+    {0x89150000u, 40u}, // vic -> Latn
+    {0xD5150000u, 40u}, // viv -> Latn
+    {0xC9750000u, 40u}, // vls -> Latn
+    {0x95950000u, 40u}, // vmf -> Latn
+    {0xD9950000u, 40u}, // vmw -> Latn
+    {0x766F0000u, 40u}, // vo -> Latn
+    {0xCDD50000u, 40u}, // vot -> Latn
+    {0xBA350000u, 40u}, // vro -> Latn
+    {0xB6950000u, 40u}, // vun -> Latn
+    {0xCE950000u, 40u}, // vut -> Latn
+    {0x77610000u, 40u}, // wa -> Latn
+    {0x90160000u, 40u}, // wae -> Latn
+    {0xA4160000u, 40u}, // waj -> Latn
     {0xAC160000u, 18u}, // wal -> Ethi
-    {0xC4160000u, 41u}, // war -> Latn
-    {0xBC360000u, 41u}, // wbp -> Latn
-    {0xC0360000u, 76u}, // wbq -> Telu
+    {0xB4160000u, 40u}, // wan -> Latn
+    {0xC4160000u, 40u}, // war -> Latn
+    {0xBC360000u, 40u}, // wbp -> Latn
+    {0xC0360000u, 77u}, // wbq -> Telu
     {0xC4360000u, 16u}, // wbr -> Deva
-    {0xC9760000u, 41u}, // wls -> Latn
+    {0xA0560000u, 40u}, // wci -> Latn
+    {0xC4960000u, 40u}, // wer -> Latn
+    {0xA0D60000u, 40u}, // wgi -> Latn
+    {0x98F60000u, 40u}, // whg -> Latn
+    {0x85160000u, 40u}, // wib -> Latn
+    {0xD1160000u, 40u}, // wiu -> Latn
+    {0xD5160000u, 40u}, // wiv -> Latn
+    {0x81360000u, 40u}, // wja -> Latn
+    {0xA1360000u, 40u}, // wji -> Latn
+    {0xC9760000u, 40u}, // wls -> Latn
+    {0xB9960000u, 40u}, // wmo -> Latn
+    {0x89B60000u, 40u}, // wnc -> Latn
     {0xA1B60000u,  1u}, // wni -> Arab
-    {0x776F0000u, 41u}, // wo -> Latn
+    {0xD1B60000u, 40u}, // wnu -> Latn
+    {0x776F0000u, 40u}, // wo -> Latn
+    {0x85D60000u, 40u}, // wob -> Latn
+    {0xC9D60000u, 40u}, // wos -> Latn
+    {0xCA360000u, 40u}, // wrs -> Latn
+    {0xAA560000u, 40u}, // wsk -> Latn
     {0xB2760000u, 16u}, // wtm -> Deva
     {0xD2960000u, 24u}, // wuu -> Hans
-    {0xD4170000u, 41u}, // xav -> Latn
+    {0xD6960000u, 40u}, // wuv -> Latn
+    {0x82D60000u, 40u}, // wwa -> Latn
+    {0xD4170000u, 40u}, // xav -> Latn
+    {0xA0370000u, 40u}, // xbi -> Latn
     {0xC4570000u, 10u}, // xcr -> Cari
-    {0x78680000u, 41u}, // xh -> Latn
-    {0x89770000u, 45u}, // xlc -> Lyci
-    {0x8D770000u, 46u}, // xld -> Lydi
+    {0xC8970000u, 40u}, // xes -> Latn
+    {0x78680000u, 40u}, // xh -> Latn
+    {0x81770000u, 40u}, // xla -> Latn
+    {0x89770000u, 44u}, // xlc -> Lyci
+    {0x8D770000u, 45u}, // xld -> Lydi
     {0x95970000u, 19u}, // xmf -> Geor
-    {0xB5970000u, 48u}, // xmn -> Mani
-    {0xC5970000u, 49u}, // xmr -> Merc
-    {0x81B70000u, 54u}, // xna -> Narb
+    {0xB5970000u, 47u}, // xmn -> Mani
+    {0xC5970000u, 48u}, // xmr -> Merc
+    {0x81B70000u, 53u}, // xna -> Narb
     {0xC5B70000u, 16u}, // xnr -> Deva
-    {0x99D70000u, 41u}, // xog -> Latn
+    {0x99D70000u, 40u}, // xog -> Latn
+    {0xB5D70000u, 40u}, // xon -> Latn
     {0xC5F70000u, 63u}, // xpr -> Prti
+    {0x86370000u, 40u}, // xrb -> Latn
     {0x82570000u, 66u}, // xsa -> Sarb
+    {0xA2570000u, 40u}, // xsi -> Latn
+    {0xB2570000u, 40u}, // xsm -> Latn
     {0xC6570000u, 16u}, // xsr -> Deva
-    {0xB8180000u, 41u}, // yao -> Latn
-    {0xBC180000u, 41u}, // yap -> Latn
-    {0xD4180000u, 41u}, // yav -> Latn
-    {0x84380000u, 41u}, // ybb -> Latn
+    {0x92D70000u, 40u}, // xwe -> Latn
+    {0xB0180000u, 40u}, // yam -> Latn
+    {0xB8180000u, 40u}, // yao -> Latn
+    {0xBC180000u, 40u}, // yap -> Latn
+    {0xC8180000u, 40u}, // yas -> Latn
+    {0xCC180000u, 40u}, // yat -> Latn
+    {0xD4180000u, 40u}, // yav -> Latn
+    {0xE0180000u, 40u}, // yay -> Latn
+    {0xE4180000u, 40u}, // yaz -> Latn
+    {0x80380000u, 40u}, // yba -> Latn
+    {0x84380000u, 40u}, // ybb -> Latn
+    {0xE0380000u, 40u}, // yby -> Latn
+    {0xC4980000u, 40u}, // yer -> Latn
+    {0xC4D80000u, 40u}, // ygr -> Latn
+    {0xD8D80000u, 40u}, // ygw -> Latn
     {0x79690000u, 27u}, // yi -> Hebr
-    {0x796F0000u, 41u}, // yo -> Latn
-    {0xAE380000u, 41u}, // yrl -> Latn
-    {0x82980000u, 41u}, // yua -> Latn
-    {0x7A610000u, 41u}, // za -> Latn
-    {0x98190000u, 41u}, // zag -> Latn
+    {0xB9580000u, 40u}, // yko -> Latn
+    {0x91780000u, 40u}, // yle -> Latn
+    {0x99780000u, 40u}, // ylg -> Latn
+    {0xAD780000u, 40u}, // yll -> Latn
+    {0xAD980000u, 40u}, // yml -> Latn
+    {0x796F0000u, 40u}, // yo -> Latn
+    {0xB5D80000u, 40u}, // yon -> Latn
+    {0x86380000u, 40u}, // yrb -> Latn
+    {0x92380000u, 40u}, // yre -> Latn
+    {0xAE380000u, 40u}, // yrl -> Latn
+    {0xCA580000u, 40u}, // yss -> Latn
+    {0x82980000u, 40u}, // yua -> Latn
+    {0x92980000u, 25u}, // yue -> Hant
+    {0x9298434Eu, 24u}, // yue-CN -> Hans
+    {0xA6980000u, 40u}, // yuj -> Latn
+    {0xCE980000u, 40u}, // yut -> Latn
+    {0xDA980000u, 40u}, // yuw -> Latn
+    {0x7A610000u, 40u}, // za -> Latn
+    {0x98190000u, 40u}, // zag -> Latn
     {0xA4790000u,  1u}, // zdj -> Arab
-    {0x80990000u, 41u}, // zea -> Latn
-    {0x9CD90000u, 77u}, // zgh -> Tfng
+    {0x80990000u, 40u}, // zea -> Latn
+    {0x9CD90000u, 78u}, // zgh -> Tfng
     {0x7A680000u, 24u}, // zh -> Hans
     {0x7A684155u, 25u}, // zh-AU -> Hant
     {0x7A68424Eu, 25u}, // zh-BN -> Hant
@@ -829,9 +1437,12 @@
     {0x7A685457u, 25u}, // zh-TW -> Hant
     {0x7A685553u, 25u}, // zh-US -> Hant
     {0x7A68564Eu, 25u}, // zh-VN -> Hant
-    {0xA1990000u, 41u}, // zmi -> Latn
-    {0x7A750000u, 41u}, // zu -> Latn
-    {0x83390000u, 41u}, // zza -> Latn
+    {0x81190000u, 40u}, // zia -> Latn
+    {0xB1790000u, 40u}, // zlm -> Latn
+    {0xA1990000u, 40u}, // zmi -> Latn
+    {0x91B90000u, 40u}, // zne -> Latn
+    {0x7A750000u, 40u}, // zu -> Latn
+    {0x83390000u, 40u}, // zza -> Latn
 });
 
 std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
@@ -854,6 +1465,7 @@
     0x616D455445746869llu, // am_Ethi_ET
     0xB9804E474C61746Ellu, // amo_Latn_NG
     0xE5C049444C61746Ellu, // aoz_Latn_ID
+    0x8DE0544741726162llu, // apd_Arab_TG
     0x6172454741726162llu, // ar_Arab_EG
     0x8A20495241726D69llu, // arc_Armi_IR
     0x8A204A4F4E626174llu, // arc_Nbat_JO
@@ -896,7 +1508,6 @@
     0x88C1494E44657661llu, // bgc_Deva_IN
     0xB4C1504B41726162llu, // bgn_Arab_PK
     0xDCC154524772656Bllu, // bgx_Grek_TR
-    0x6268494E4B746869llu, // bh_Kthi_IN
     0x84E1494E44657661llu, // bhb_Deva_IN
     0xA0E1494E44657661llu, // bhi_Deva_IN
     0xA8E150484C61746Ellu, // bhk_Latn_PH
@@ -980,6 +1591,7 @@
     0x864344454C61746Ellu, // dsb_Latn_DE
     0xB2634D4C4C61746Ellu, // dtm_Latn_ML
     0xBE634D594C61746Ellu, // dtp_Latn_MY
+    0xE2634E5044657661llu, // dty_Deva_NP
     0x8283434D4C61746Ellu, // dua_Latn_CM
     0x64764D5654686161llu, // dv_Thaa_MV
     0xBB03534E4C61746Ellu, // dyo_Latn_SN
@@ -1006,6 +1618,7 @@
     0xCEE445534C61746Ellu, // ext_Latn_ES
     0x6661495241726162llu, // fa_Arab_IR
     0xB40547514C61746Ellu, // fan_Latn_GQ
+    0x6666474E41646C6Dllu, // ff_Adlm_GN
     0x6666534E4C61746Ellu, // ff_Latn_SN
     0xB0A54D4C4C61746Ellu, // ffm_Latn_ML
     0x666946494C61746Ellu, // fi_Latn_FI
@@ -1020,7 +1633,9 @@
     0xBE2546524C61746Ellu, // frp_Latn_FR
     0xC62544454C61746Ellu, // frr_Latn_DE
     0xCA2544454C61746Ellu, // frs_Latn_DE
+    0x8685434D41726162llu, // fub_Arab_CM
     0x8E8557464C61746Ellu, // fud_Latn_WF
+    0x9685474E4C61746Ellu, // fuf_Latn_GN
     0xC2854E454C61746Ellu, // fuq_Latn_NE
     0xC68549544C61746Ellu, // fur_Latn_IT
     0xD6854E474C61746Ellu, // fuv_Latn_NG
@@ -1104,7 +1719,6 @@
     0x6A614A504A70616Ellu, // ja_Jpan_JP
     0xB0094A4D4C61746Ellu, // jam_Latn_JM
     0xB8C9434D4C61746Ellu, // jgo_Latn_CM
-    0x6A69554148656272llu, // ji_Hebr_UA
     0x8989545A4C61746Ellu, // jmc_Latn_TZ
     0xAD894E5044657661llu, // jml_Deva_NP
     0xCE89444B4C61746Ellu, // jut_Latn_DK
@@ -1118,9 +1732,11 @@
     0xB00A4B454C61746Ellu, // kam_Latn_KE
     0xB80A4D4C4C61746Ellu, // kao_Latn_ML
     0x8C2A52554379726Cllu, // kbd_Cyrl_RU
+    0xE02A4E4541726162llu, // kby_Arab_NE
     0x984A4E474C61746Ellu, // kcg_Latn_NG
     0xA84A5A574C61746Ellu, // kck_Latn_ZW
     0x906A545A4C61746Ellu, // kde_Latn_TZ
+    0x9C6A544741726162llu, // kdh_Arab_TG
     0xCC6A544854686169llu, // kdt_Thai_TH
     0x808A43564C61746Ellu, // kea_Latn_CV
     0xB48A434D4C61746Ellu, // ken_Latn_CM
@@ -1251,7 +1867,7 @@
     0x6D72494E44657661llu, // mr_Deva_IN
     0x8E2C4E5044657661llu, // mrd_Deva_NP
     0xA62C52554379726Cllu, // mrj_Cyrl_RU
-    0xD22C42444D726F6Fllu, // mru_Mroo_BD
+    0xBA2C42444D726F6Fllu, // mro_Mroo_BD
     0x6D734D594C61746Ellu, // ms_Latn_MY
     0x6D744D544C61746Ellu, // mt_Latn_MT
     0xC66C494E44657661llu, // mtr_Deva_IN
@@ -1308,6 +1924,7 @@
     0x6F6D45544C61746Ellu, // om_Latn_ET
     0x6F72494E4F727961llu, // or_Orya_IN
     0x6F7347454379726Cllu, // os_Cyrl_GE
+    0x824E55534F736765llu, // osa_Osge_US
     0xAA6E4D4E4F726B68llu, // otk_Orkh_MN
     0x7061504B41726162llu, // pa_Arab_PK
     0x7061494E47757275llu, // pa_Guru_IN
@@ -1479,6 +2096,7 @@
     0xB2934D574C61746Ellu, // tum_Latn_MW
     0xAEB354564C61746Ellu, // tvl_Latn_TV
     0xC2D34E454C61746Ellu, // twq_Latn_NE
+    0x9AF3434E54616E67llu, // txg_Tang_CN
     0x747950464C61746Ellu, // ty_Latn_PF
     0xD71352554379726Cllu, // tyv_Cyrl_RU
     0xB3334D414C61746Ellu, // tzm_Latn_MA
@@ -1540,14 +2158,18 @@
     0x796F4E474C61746Ellu, // yo_Latn_NG
     0xAE3842524C61746Ellu, // yrl_Latn_BR
     0x82984D584C61746Ellu, // yua_Latn_MX
+    0x9298434E48616E73llu, // yue_Hans_CN
+    0x9298484B48616E74llu, // yue_Hant_HK
     0x7A61434E4C61746Ellu, // za_Latn_CN
     0x981953444C61746Ellu, // zag_Latn_SD
     0xA4794B4D41726162llu, // zdj_Arab_KM
     0x80994E4C4C61746Ellu, // zea_Latn_NL
     0x9CD94D4154666E67llu, // zgh_Tfng_MA
     0x7A685457426F706Fllu, // zh_Bopo_TW
+    0x7A68545748616E62llu, // zh_Hanb_TW
     0x7A68434E48616E73llu, // zh_Hans_CN
     0x7A68545748616E74llu, // zh_Hant_TW
+    0xB17954474C61746Ellu, // zlm_Latn_TG
     0xA1994D594C61746Ellu, // zmi_Latn_MY
     0x7A755A414C61746Ellu, // zu_Latn_ZA
     0x833954524C61746Ellu, // zza_Latn_TR
@@ -1662,6 +2284,7 @@
     {0x656E5A57u, 0x656E8400u}, // en-ZW -> en-001
     {0x65734152u, 0x6573A424u}, // es-AR -> es-419
     {0x6573424Fu, 0x6573A424u}, // es-BO -> es-419
+    {0x65734252u, 0x6573A424u}, // es-BR -> es-419
     {0x6573434Cu, 0x6573A424u}, // es-CL -> es-419
     {0x6573434Fu, 0x6573A424u}, // es-CO -> es-419
     {0x65734352u, 0x6573A424u}, // es-CR -> es-419
@@ -1681,8 +2304,11 @@
     {0x65735559u, 0x6573A424u}, // es-UY -> es-419
     {0x65735645u, 0x6573A424u}, // es-VE -> es-419
     {0x7074414Fu, 0x70745054u}, // pt-AO -> pt-PT
+    {0x70744348u, 0x70745054u}, // pt-CH -> pt-PT
     {0x70744356u, 0x70745054u}, // pt-CV -> pt-PT
+    {0x70744751u, 0x70745054u}, // pt-GQ -> pt-PT
     {0x70744757u, 0x70745054u}, // pt-GW -> pt-PT
+    {0x70744C55u, 0x70745054u}, // pt-LU -> pt-PT
     {0x70744D4Fu, 0x70745054u}, // pt-MO -> pt-PT
     {0x70744D5Au, 0x70745054u}, // pt-MZ -> pt-PT
     {0x70745354u, 0x70745054u}, // pt-ST -> pt-PT
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 7fbfffe..a4bcc62 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -140,7 +140,7 @@
     patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t));
 }
 
-inline void Res_value::copyFrom_dtoh(const Res_value& src)
+void Res_value::copyFrom_dtoh(const Res_value& src)
 {
     size = dtohs(src.size);
     res0 = src.res0;
@@ -1907,6 +1907,8 @@
     if (diff != 0) return diff;
     diff = (int32_t)(screenLayout2 - o.screenLayout2);
     if (diff != 0) return diff;
+    diff = (int32_t)(colorimetry - o.colorimetry);
+    if (diff != 0) return diff;
     diff = (int32_t)(uiMode - o.uiMode);
     if (diff != 0) return diff;
     diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
@@ -1967,6 +1969,9 @@
     if (screenLayout2 != o.screenLayout2) {
         return screenLayout2 < o.screenLayout2 ? -1 : 1;
     }
+    if (colorimetry != o.colorimetry) {
+        return colorimetry < o.colorimetry ? -1 : 1;
+    }
     if (uiMode != o.uiMode) {
         return uiMode < o.uiMode ? -1 : 1;
     }
@@ -1992,6 +1997,8 @@
     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
     if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
     if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
+    if ((colorimetry & MASK_WIDE_COLOR_GAMUT) != (o.colorimetry & MASK_WIDE_COLOR_GAMUT)) diffs |= CONFIG_COLORIMETRY;
+    if ((colorimetry & MASK_HDR) != (o.colorimetry & MASK_HDR)) diffs |= CONFIG_COLORIMETRY;
     if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
     if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
     if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
@@ -2103,6 +2110,17 @@
         }
     }
 
+    if (colorimetry || o.colorimetry) {
+        if (((colorimetry^o.colorimetry) & MASK_HDR) != 0) {
+            if (!(colorimetry & MASK_HDR)) return false;
+            if (!(o.colorimetry & MASK_HDR)) return true;
+        }
+        if (((colorimetry^o.colorimetry) & MASK_WIDE_COLOR_GAMUT) != 0) {
+            if (!(colorimetry & MASK_WIDE_COLOR_GAMUT)) return false;
+            if (!(o.colorimetry & MASK_WIDE_COLOR_GAMUT)) return true;
+        }
+    }
+
     if (orientation != o.orientation) {
         if (!orientation) return false;
         if (!o.orientation) return true;
@@ -2390,6 +2408,17 @@
             }
         }
 
+        if (colorimetry || o.colorimetry) {
+            if (((colorimetry^o.colorimetry) & MASK_WIDE_COLOR_GAMUT) != 0 &&
+                    (requested->colorimetry & MASK_WIDE_COLOR_GAMUT)) {
+                return colorimetry & MASK_WIDE_COLOR_GAMUT;
+            }
+            if (((colorimetry^o.colorimetry) & MASK_HDR) != 0 &&
+                    (requested->colorimetry & MASK_HDR)) {
+                return colorimetry & MASK_HDR;
+            }
+        }
+
         if ((orientation != o.orientation) && requested->orientation) {
             return (orientation);
         }
@@ -2639,6 +2668,18 @@
         if (screenRound != 0 && screenRound != setScreenRound) {
             return false;
         }
+
+        const int hdr = colorimetry & MASK_HDR;
+        const int setHdr = settings.colorimetry & MASK_HDR;
+        if (hdr != 0 && hdr != setHdr) {
+            return false;
+        }
+
+        const int wideColorGamut = colorimetry & MASK_WIDE_COLOR_GAMUT;
+        const int setWideColorGamut = settings.colorimetry & MASK_WIDE_COLOR_GAMUT;
+        if (wideColorGamut != 0 && wideColorGamut != setWideColorGamut) {
+            return false;
+        }
     }
 
     if (screenSizeDp != 0) {
@@ -2959,6 +3000,34 @@
                 break;
         }
     }
+    if ((colorimetry&MASK_HDR) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (colorimetry&MASK_HDR) {
+            case ResTable_config::HDR_NO:
+                res.append("lowdr");
+                break;
+            case ResTable_config::HDR_YES:
+                res.append("highdr");
+                break;
+            default:
+                res.appendFormat("hdr=%d", dtohs(colorimetry&MASK_HDR));
+                break;
+        }
+    }
+    if ((colorimetry&MASK_WIDE_COLOR_GAMUT) != 0) {
+        if (res.size() > 0) res.append("-");
+        switch (colorimetry&MASK_WIDE_COLOR_GAMUT) {
+            case ResTable_config::WIDE_COLOR_GAMUT_NO:
+                res.append("nowidecg");
+                break;
+            case ResTable_config::WIDE_COLOR_GAMUT_YES:
+                res.append("widecg");
+                break;
+            default:
+                res.appendFormat("wideColorGamut=%d", dtohs(colorimetry&MASK_WIDE_COLOR_GAMUT));
+                break;
+        }
+    }
     if (orientation != ORIENTATION_ANY) {
         if (res.size() > 0) res.append("-");
         switch (orientation) {
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
new file mode 100644
index 0000000..a3d67f0
--- /dev/null
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef APKASSETS_H_
+#define APKASSETS_H_
+
+#include <memory>
+#include <string>
+
+#include "android-base/macros.h"
+#include "ziparchive/zip_archive.h"
+
+#include "androidfw/Asset.h"
+#include "androidfw/LoadedArsc.h"
+
+namespace android {
+
+// Holds an APK.
+class ApkAssets {
+ public:
+  static std::unique_ptr<ApkAssets> Load(const std::string& path);
+
+  std::unique_ptr<Asset> Open(const std::string& path,
+                              Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
+
+  inline const std::string& GetPath() const { return path_; }
+
+  inline const LoadedArsc* GetLoadedArsc() const { return loaded_arsc_.get(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ApkAssets);
+
+  ApkAssets() = default;
+
+  struct ZipArchivePtrCloser {
+    void operator()(::ZipArchiveHandle handle) { ::CloseArchive(handle); }
+  };
+
+  using ZipArchivePtr =
+      std::unique_ptr<typename std::remove_pointer<::ZipArchiveHandle>::type, ZipArchivePtrCloser>;
+  ZipArchivePtr zip_handle_;
+  std::string path_;
+  std::unique_ptr<Asset> resources_asset_;
+  std::unique_ptr<LoadedArsc> loaded_arsc_;
+};
+
+}  // namespace android
+
+#endif /* APKASSETS_H_ */
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
new file mode 100644
index 0000000..66d5034
--- /dev/null
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROIDFW_ASSETMANAGER2_H_
+#define ANDROIDFW_ASSETMANAGER2_H_
+
+#include "android-base/macros.h"
+
+#include <limits>
+#include <unordered_map>
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/Util.h"
+
+namespace android {
+
+class Theme;
+
+using ApkAssetsCookie = int32_t;
+
+enum : ApkAssetsCookie {
+  kInvalidCookie = -1,
+};
+
+// Holds a bag that has been merged with its parent, if one exists.
+struct ResolvedBag {
+  // A single key-value entry in a bag.
+  struct Entry {
+    // The key, as described in ResTable_map::name.
+    uint32_t key;
+
+    Res_value value;
+
+    // Which ApkAssets this entry came from.
+    ApkAssetsCookie cookie;
+
+    ResStringPool* key_pool;
+    ResStringPool* type_pool;
+  };
+
+  // Denotes the configuration axis that this bag varies with.
+  // If a configuration changes with respect to one of these axis,
+  // the bag should be reloaded.
+  uint32_t type_spec_flags;
+
+  // The number of entries in this bag. Access them by indexing into `entries`.
+  uint32_t entry_count;
+
+  // The array of entries for this bag. An empty array is a neat trick to force alignment
+  // of the Entry structs that follow this structure and avoids a bunch of casts.
+  Entry entries[0];
+};
+
+// AssetManager2 is the main entry point for accessing assets and resources.
+// AssetManager2 provides caching of resources retrieved via the underlying
+// ApkAssets.
+class AssetManager2 : public ::AAssetManager {
+ public:
+  struct ResourceName {
+    const char* package = nullptr;
+    size_t package_len = 0u;
+
+    const char* type = nullptr;
+    const char16_t* type16 = nullptr;
+    size_t type_len = 0u;
+
+    const char* entry = nullptr;
+    const char16_t* entry16 = nullptr;
+    size_t entry_len = 0u;
+  };
+
+  AssetManager2();
+
+  // Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets
+  // are not owned by the AssetManager, and must have a longer lifetime.
+  //
+  // Only pass invalidate_caches=false when it is known that the structure
+  // change in ApkAssets is due to a safe addition of resources with completely
+  // new resource IDs.
+  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+
+  const std::vector<const ApkAssets*> GetApkAssets() const;
+
+  // Returns the string pool for the given asset cookie.
+  // Use the string pool returned here with a valid Res_value object of
+  // type Res_value::TYPE_STRING.
+  const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const;
+
+  // Sets/resets the configuration for this AssetManager. This will cause all
+  // caches that are related to the configuration change to be invalidated.
+  void SetConfiguration(const ResTable_config& configuration);
+
+  const ResTable_config& GetConfiguration() const;
+
+  // Searches the set of APKs loaded by this AssetManager and opens the first one found located
+  // in the assets/ directory.
+  // `mode` controls how the file is opened.
+  //
+  // NOTE: The loaded APKs are searched in reverse order.
+  std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode);
+
+  // Opens a file within the assets/ directory of the APK specified by `cookie`.
+  // `mode` controls how the file is opened.
+  std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
+                              Asset::AccessMode mode);
+
+  // Searches the set of APKs loaded by this AssetManager and opens the first one found.
+  // `mode` controls how the file is opened.
+  // `out_cookie` is populated with the cookie of the APK this file was found in.
+  //
+  // NOTE: The loaded APKs are searched in reverse order.
+  std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
+                                      ApkAssetsCookie* out_cookie = nullptr);
+
+  // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
+  // This is typically used to open a specific AndroidManifest.xml, or a binary XML file
+  // referenced by a resource lookup with GetResource().
+  std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
+                                      Asset::AccessMode mode);
+
+  // Populates the `out_name` parameter with resource name information.
+  // Utf8 strings are preferred, and only if they are unavailable are
+  // the Utf16 variants populated.
+  // Returns false if the resource was not found or the name was missing/corrupt.
+  bool GetResourceName(uint32_t resid, ResourceName* out_name);
+
+  // Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
+  // See ResTable_config for the list of configuration axis.
+  // Returns false if the resource was not found.
+  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
+
+  // Retrieves the best matching resource with ID `resid`. The resource value is filled into
+  // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
+  // `out_flags` holds the same flags as retrieved with GetResourceFlags().
+  // If `density_override` is non-zero, the configuration to match against is overridden with that
+  // density.
+  //
+  // Returns a valid cookie if the resource was found. If the resource was not found, or if the
+  // resource was a map/bag type, then kInvalidCookie is returned. If `may_be_bag` is false,
+  // this function logs if the resource was a map/bag type before returning kInvalidCookie.
+  ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
+                              Res_value* out_value, ResTable_config* out_selected_config,
+                              uint32_t* out_flags);
+
+  // Retrieves the best matching bag/map resource with ID `resid`.
+  // This method will resolve all parent references for this bag and merge keys with the child.
+  // To iterate over the keys, use the following idiom:
+  //
+  //  const AssetManager2::ResolvedBag* bag = asset_manager->GetBag(id);
+  //  if (bag != nullptr) {
+  //    for (auto iter = begin(bag); iter != end(bag); ++iter) {
+  //      ...
+  //    }
+  //  }
+  const ResolvedBag* GetBag(uint32_t resid);
+
+  // Creates a new Theme from this AssetManager.
+  std::unique_ptr<Theme> NewTheme();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AssetManager2);
+
+  // Finds the best entry for `resid` amongst all the ApkAssets. The entry can be a simple
+  // Res_value, or a complex map/bag type.
+  //
+  // `density_override` overrides the density of the current configuration when doing a search.
+  //
+  // When `stop_at_first_match` is true, the first match found is selected and the search
+  // terminates. This is useful for methods that just look up the name of a resource and don't
+  // care about the value. In this case, the value of `out_flags` is incomplete and should not
+  // be used.
+  //
+  // `out_flags` stores the resulting bitmask of configuration axis with which the resource
+  // value varies.
+  ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
+                            LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+                            uint32_t* out_flags);
+
+  // Purge all resources that are cached and vary by the configuration axis denoted by the
+  // bitmask `diff`.
+  void InvalidateCaches(uint32_t diff);
+
+  // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
+  // have a longer lifetime.
+  std::vector<const ApkAssets*> apk_assets_;
+
+  // The current configuration set for this AssetManager. When this changes, cached resources
+  // may need to be purged.
+  ResTable_config configuration_;
+
+  // Cached set of bags. These are cached because they can inherit keys from parent bags,
+  // which involves some calculation.
+  std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+};
+
+class Theme {
+  friend class AssetManager2;
+
+ public:
+  // Applies the style identified by `resid` to this theme. This can be called
+  // multiple times with different styles. By default, any theme attributes that
+  // are already defined before this call are not overridden. If `force` is set
+  // to true, this behavior is changed and all theme attributes from the style at
+  // `resid` are applied.
+  // Returns false if the style failed to apply.
+  bool ApplyStyle(uint32_t resid, bool force = false);
+
+  // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
+  // Returns false if the AssetManagers of the Themes were not compatible.
+  bool SetTo(const Theme& o);
+
+  void Clear();
+
+  inline const AssetManager2* GetAssetManager() const { return asset_manager_; }
+
+  // Returns a bit mask of configuration changes that will impact this
+  // theme (and thus require completely reloading it).
+  inline uint32_t GetChangingConfigurations() const { return type_spec_flags_; }
+
+  // Retrieve a value in the theme. If the theme defines this value,
+  // returns an asset cookie indicating which ApkAssets it came from
+  // and populates `out_value` with the value. If `out_flags` is non-null,
+  // populates it with a bitmask of the configuration axis the resource
+  // varies with.
+  //
+  // If the attribute is not found, returns kInvalidCookie.
+  //
+  // NOTE: This function does not do reference traversal. If you want
+  // to follow references to other resources to get the "real" value to
+  // use, you need to call ResolveReference() after this function.
+  ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value,
+                               uint32_t* out_flags = nullptr) const;
+
+  // This is like AssetManager2::ResolveReference(), but also takes
+  // care of resolving attribute references to the theme.
+  ApkAssetsCookie ResolveAttributeReference(Res_value* in_out_value, ApkAssetsCookie src_cookie,
+                                            uint32_t* out_last_ref = nullptr,
+                                            uint32_t* in_out_type_spec_flags = nullptr,
+                                            ResTable_config* out_selected_config = nullptr) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Theme);
+
+  // Called by AssetManager2.
+  explicit inline Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {}
+
+  struct Entry {
+    ApkAssetsCookie cookie;
+    uint32_t type_spec_flags;
+    Res_value value;
+  };
+
+  struct Type {
+    // Use uint32_t for fewer cycles when loading from memory.
+    uint32_t entry_count;
+    uint32_t entry_capacity;
+    Entry entries[0];
+  };
+
+  static constexpr const size_t kPackageCount = std::numeric_limits<uint8_t>::max() + 1;
+  static constexpr const size_t kTypeCount = std::numeric_limits<uint8_t>::max() + 1;
+
+  struct Package {
+    // Each element of Type will be a dynamically sized object
+    // allocated to have the entries stored contiguously with the Type.
+    util::unique_cptr<Type> types[kTypeCount];
+  };
+
+  AssetManager2* asset_manager_;
+  uint32_t type_spec_flags_ = 0u;
+  std::unique_ptr<Package> packages_[kPackageCount];
+};
+
+inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) { return bag->entries; }
+
+inline const ResolvedBag::Entry* end(const ResolvedBag* bag) {
+  return bag->entries + bag->entry_count;
+}
+
+}  // namespace android
+
+#endif /* ANDROIDFW_ASSETMANAGER2_H_ */
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index 87c6b12..d84a207 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -17,9 +17,10 @@
 #ifndef __BYTE_BUCKET_ARRAY_H
 #define __BYTE_BUCKET_ARRAY_H
 
-#include <utils/Log.h>
-#include <stdint.h>
-#include <string.h>
+#include <cstdint>
+#include <cstring>
+
+#include "android-base/logging.h"
 
 namespace android {
 
@@ -27,71 +28,65 @@
  * Stores a sparsely populated array. Has a fixed size of 256
  * (number of entries that a byte can represent).
  */
-template<typename T>
+template <typename T>
 class ByteBucketArray {
-public:
-    ByteBucketArray() : mDefault() {
-        memset(mBuckets, 0, sizeof(mBuckets));
+ public:
+  ByteBucketArray() : default_() { memset(buckets_, 0, sizeof(buckets_)); }
+
+  ~ByteBucketArray() {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      if (buckets_[i] != NULL) {
+        delete[] buckets_[i];
+      }
+    }
+    memset(buckets_, 0, sizeof(buckets_));
+  }
+
+  inline size_t size() const { return kNumBuckets * kBucketSize; }
+
+  inline const T& get(size_t index) const { return (*this)[index]; }
+
+  const T& operator[](size_t index) const {
+    if (index >= size()) {
+      return default_;
     }
 
-    ~ByteBucketArray() {
-        for (size_t i = 0; i < NUM_BUCKETS; i++) {
-            if (mBuckets[i] != NULL) {
-                delete [] mBuckets[i];
-            }
-        }
-        memset(mBuckets, 0, sizeof(mBuckets));
+    uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
+    T* bucket = buckets_[bucket_index];
+    if (bucket == NULL) {
+      return default_;
+    }
+    return bucket[0x0f & static_cast<uint8_t>(index)];
+  }
+
+  T& editItemAt(size_t index) {
+    CHECK(index < size()) << "ByteBucketArray.getOrCreate(index=" << index
+                          << ") with size=" << size();
+
+    uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
+    T* bucket = buckets_[bucket_index];
+    if (bucket == NULL) {
+      bucket = buckets_[bucket_index] = new T[kBucketSize]();
+    }
+    return bucket[0x0f & static_cast<uint8_t>(index)];
+  }
+
+  bool set(size_t index, const T& value) {
+    if (index >= size()) {
+      return false;
     }
 
-    inline size_t size() const {
-        return NUM_BUCKETS * BUCKET_SIZE;
-    }
+    editItemAt(index) = value;
+    return true;
+  }
 
-    inline const T& get(size_t index) const {
-        return (*this)[index];
-    }
+ private:
+  enum { kNumBuckets = 16, kBucketSize = 16 };
 
-    const T& operator[](size_t index) const {
-        if (index >= size()) {
-            return mDefault;
-        }
-
-        uint8_t bucketIndex = static_cast<uint8_t>(index) >> 4;
-        T* bucket = mBuckets[bucketIndex];
-        if (bucket == NULL) {
-            return mDefault;
-        }
-        return bucket[0x0f & static_cast<uint8_t>(index)];
-    }
-
-    T& editItemAt(size_t index) {
-        ALOG_ASSERT(index < size(), "ByteBucketArray.getOrCreate(index=%u) with size=%u",
-                (uint32_t) index, (uint32_t) size());
-
-        uint8_t bucketIndex = static_cast<uint8_t>(index) >> 4;
-        T* bucket = mBuckets[bucketIndex];
-        if (bucket == NULL) {
-            bucket = mBuckets[bucketIndex] = new T[BUCKET_SIZE]();
-        }
-        return bucket[0x0f & static_cast<uint8_t>(index)];
-    }
-
-    bool set(size_t index, const T& value) {
-        if (index >= size()) {
-            return false;
-        }
-
-        editItemAt(index) = value;
-        return true;
-    }
-
-private:
-    enum { NUM_BUCKETS = 16, BUCKET_SIZE = 16 };
-
-    T*  mBuckets[NUM_BUCKETS];
-    T   mDefault;
+  T* buckets_[kNumBuckets];
+  T default_;
 };
 
-} // namespace android
+}  // namespace android
 
-#endif // __BYTE_BUCKET_ARRAY_H
+#endif  // __BYTE_BUCKET_ARRAY_H
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
new file mode 100644
index 0000000..e2e56c8
--- /dev/null
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef LOADEDARSC_H_
+#define LOADEDARSC_H_
+
+#include <memory>
+#include <vector>
+
+#include "android-base/macros.h"
+
+#include "androidfw/ResourceTypes.h"
+
+namespace android {
+
+class Chunk;
+class LoadedPackage;
+
+// Read-only view into a resource table. This class validates all data
+// when loading, including offsets and lengths.
+class LoadedArsc {
+ public:
+  // Load the resource table from memory. The data's lifetime must out-live the
+  // object returned from this method.
+  static std::unique_ptr<LoadedArsc> Load(const void* data, size_t len);
+
+  ~LoadedArsc();
+
+  // Returns the string pool where all string resource values
+  // (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
+  inline const ResStringPool* GetStringPool() const { return &global_string_pool_; }
+
+  struct Entry {
+    // A pointer to the resource table entry for this resource.
+    // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+    // a ResTable_map_entry and processed as a bag/map.
+    const ResTable_entry* entry = nullptr;
+
+    // The string pool reference to the type's name. This uses a different string pool than
+    // the global string pool, but this is hidden from the caller.
+    StringPoolRef type_string_ref;
+
+    // The string pool reference to the entry's name. This uses a different string pool than
+    // the global string pool, but this is hidden from the caller.
+    StringPoolRef entry_string_ref;
+  };
+
+  // Finds the resource with ID `resid` with the best value for configuration `config`.
+  // The parameter `out_entry` will be filled with the resulting resource entry.
+  // The resource entry can be a simple entry (ResTable_entry) or a complex bag
+  // (ResTable_entry_map).
+  bool FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry,
+                 ResTable_config* selected_config, uint32_t* out_flags) const;
+
+  // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
+  const std::string* GetPackageNameForId(uint32_t resid) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
+
+  LoadedArsc() = default;
+  bool LoadTable(const Chunk& chunk);
+
+  ResStringPool global_string_pool_;
+  std::vector<std::unique_ptr<LoadedPackage>> packages_;
+};
+
+}  // namespace android
+
+#endif /* LOADEDARSC_H_ */
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 33b91b9..1e4aee9 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -265,7 +265,7 @@
     uint8_t res0;
         
     // Type of the data value.
-    enum {
+    enum : uint8_t {
         // The 'data' is either 0 or 1, specifying this resource is either
         // undefined or empty, respectively.
         TYPE_NULL = 0x00,
@@ -1146,11 +1146,26 @@
         SCREENROUND_YES = ACONFIGURATION_SCREENROUND_YES,
     };
 
+    enum {
+        // colorimetry bits for wide-color gamut/narrow-color gamut.
+        MASK_WIDE_COLOR_GAMUT = 0x03,
+        WIDE_COLOR_GAMUT_ANY = ACONFIGURATION_WIDE_COLOR_GAMUT_ANY,
+        WIDE_COLOR_GAMUT_NO = ACONFIGURATION_WIDE_COLOR_GAMUT_NO,
+        WIDE_COLOR_GAMUT_YES = ACONFIGURATION_WIDE_COLOR_GAMUT_YES,
+
+        // colorimetry bits for HDR/LDR.
+        MASK_HDR = 0x0c,
+        SHIFT_COLORIMETRY_HDR = 2,
+        HDR_ANY = ACONFIGURATION_HDR_ANY << SHIFT_COLORIMETRY_HDR,
+        HDR_NO = ACONFIGURATION_HDR_NO << SHIFT_COLORIMETRY_HDR,
+        HDR_YES = ACONFIGURATION_HDR_YES << SHIFT_COLORIMETRY_HDR,
+    };
+
     // An extension of screenConfig.
     union {
         struct {
             uint8_t screenLayout2;      // Contains round/notround qualifier.
-            uint8_t screenConfigPad1;   // Reserved padding.
+            uint8_t colorimetry;        // Wide-gamut, HDR, etc.
             uint16_t screenConfigPad2;  // Reserved padding.
         };
         uint32_t screenConfig2;
@@ -1193,6 +1208,7 @@
         CONFIG_UI_MODE = ACONFIGURATION_UI_MODE,
         CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR,
         CONFIG_SCREEN_ROUND = ACONFIGURATION_SCREEN_ROUND,
+        CONFIG_COLORIMETRY = ACONFIGURATION_COLORIMETRY,
     };
     
     // Compare two configuration, returning CONFIG_* flags set for each value
diff --git a/tools/aapt2/util/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
similarity index 66%
rename from tools/aapt2/util/StringPiece.h
rename to libs/androidfw/include/androidfw/StringPiece.h
index 5144b1f..c9effd1 100644
--- a/tools/aapt2/util/StringPiece.h
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -14,26 +14,24 @@
  * limitations under the License.
  */
 
-#ifndef AAPT_STRING_PIECE_H
-#define AAPT_STRING_PIECE_H
+#ifndef ANDROIDFW_STRING_PIECE_H
+#define ANDROIDFW_STRING_PIECE_H
 
 #include <ostream>
 #include <string>
 
 #include "utils/JenkinsHash.h"
-#include "utils/String8.h"
 #include "utils/Unicode.h"
 
-namespace aapt {
+namespace android {
 
-/**
- * Read only wrapper around basic C strings.
- * Prevents excessive copying.
- *
- * WARNING: When creating from std::basic_string<>, moving the original
- * std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
- * BasicStringPiece<> should only be used transitively.
- */
+// Read only wrapper around basic C strings. Prevents excessive copying.
+// StringPiece does not own the data it is wrapping. The lifetime of the underlying
+// data must outlive this StringPiece.
+//
+// WARNING: When creating from std::basic_string<>, moving the original
+// std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
+// BasicStringPiece<> should only be used transitively.
 template <typename TChar>
 class BasicStringPiece {
  public:
@@ -53,15 +51,14 @@
   BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
 
   BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
-  BasicStringPiece<TChar> substr(
-      BasicStringPiece<TChar>::const_iterator begin,
-      BasicStringPiece<TChar>::const_iterator end) const;
+  BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
+                                 BasicStringPiece<TChar>::const_iterator end) const;
 
   const TChar* data() const;
   size_t length() const;
   size_t size() const;
   bool empty() const;
-  std::basic_string<TChar> ToString() const;
+  std::basic_string<TChar> to_string() const;
 
   bool contains(const BasicStringPiece<TChar>& rhs) const;
   int compare(const BasicStringPiece<TChar>& rhs) const;
@@ -89,17 +86,14 @@
 constexpr const size_t BasicStringPiece<TChar>::npos;
 
 template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece()
-    : data_(nullptr), length_(0) {}
+inline BasicStringPiece<TChar>::BasicStringPiece() : data_(nullptr), length_(0) {}
 
 template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece(
-    const BasicStringPiece<TChar>& str)
+inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str)
     : data_(str.data_), length_(str.length_) {}
 
 template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece(
-    const std::basic_string<TChar>& str)
+inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str)
     : data_(str.data()), length_(str.length()) {}
 
 template <>
@@ -123,16 +117,14 @@
 }
 
 template <typename TChar>
-inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(
-    const TChar* str, size_t len) {
+inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
   data_ = str;
   length_ = len;
   return *this;
 }
 
 template <typename TChar>
-inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
-    size_t start, size_t len) const {
+inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
   if (len == npos) {
     len = length_ - start;
   }
@@ -171,13 +163,12 @@
 }
 
 template <typename TChar>
-inline std::basic_string<TChar> BasicStringPiece<TChar>::ToString() const {
+inline std::basic_string<TChar> BasicStringPiece<TChar>::to_string() const {
   return std::basic_string<TChar>(data_, length_);
 }
 
 template <>
-inline bool BasicStringPiece<char>::contains(
-    const BasicStringPiece<char>& rhs) const {
+inline bool BasicStringPiece<char>::contains(const BasicStringPiece<char>& rhs) const {
   if (!data_ || !rhs.data_) {
     return false;
   }
@@ -188,8 +179,7 @@
 }
 
 template <>
-inline int BasicStringPiece<char>::compare(
-    const BasicStringPiece<char>& rhs) const {
+inline int BasicStringPiece<char>::compare(const BasicStringPiece<char>& rhs) const {
   const char nullStr = '\0';
   const char* b1 = data_ != nullptr ? data_ : &nullStr;
   const char* e1 = b1 + length_;
@@ -205,15 +195,21 @@
   return static_cast<int>(length_ - rhs.length_);
 }
 
-inline ::std::ostream& operator<<(::std::ostream& out,
-                                  const BasicStringPiece<char16_t>& str) {
-  android::String8 utf8(str.data(), str.size());
-  return out.write(utf8.string(), utf8.size());
+inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char16_t>& str) {
+  const ssize_t result_len = utf16_to_utf8_length(str.data(), str.size());
+  if (result_len < 0) {
+    // Empty string.
+    return out;
+  }
+
+  std::string result;
+  result.resize(static_cast<size_t>(result_len));
+  utf16_to_utf8(str.data(), str.length(), &*result.begin(), static_cast<size_t>(result_len) + 1);
+  return out << result;
 }
 
 template <>
-inline bool BasicStringPiece<char16_t>::contains(
-    const BasicStringPiece<char16_t>& rhs) const {
+inline bool BasicStringPiece<char16_t>::contains(const BasicStringPiece<char16_t>& rhs) const {
   if (!data_ || !rhs.data_) {
     return false;
   }
@@ -224,8 +220,7 @@
 }
 
 template <>
-inline int BasicStringPiece<char16_t>::compare(
-    const BasicStringPiece<char16_t>& rhs) const {
+inline int BasicStringPiece<char16_t>::compare(const BasicStringPiece<char16_t>& rhs) const {
   const char16_t nullStr = u'\0';
   const char16_t* b1 = data_ != nullptr ? data_ : &nullStr;
   const char16_t* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
@@ -233,66 +228,52 @@
 }
 
 template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator<(
-    const BasicStringPiece<TChar>& rhs) const {
+inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
   return compare(rhs) < 0;
 }
 
 template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator>(
-    const BasicStringPiece<TChar>& rhs) const {
+inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
   return compare(rhs) > 0;
 }
 
 template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator==(
-    const BasicStringPiece<TChar>& rhs) const {
+inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
   return compare(rhs) == 0;
 }
 
 template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator!=(
-    const BasicStringPiece<TChar>& rhs) const {
+inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
   return compare(rhs) != 0;
 }
 
 template <typename TChar>
-inline typename BasicStringPiece<TChar>::const_iterator
-BasicStringPiece<TChar>::begin() const {
+inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
   return data_;
 }
 
 template <typename TChar>
-inline typename BasicStringPiece<TChar>::const_iterator
-BasicStringPiece<TChar>::end() const {
+inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
   return data_ + length_;
 }
 
-inline ::std::ostream& operator<<(::std::ostream& out,
-                                  const BasicStringPiece<char>& str) {
+inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
   return out.write(str.data(), str.size());
 }
 
-}  // namespace aapt
-
-inline ::std::ostream& operator<<(::std::ostream& out,
-                                  const std::u16string& str) {
-  android::String8 utf8(str.data(), str.size());
-  return out.write(utf8.string(), utf8.size());
-}
+}  // namespace android
 
 namespace std {
 
 template <typename TChar>
-struct hash<aapt::BasicStringPiece<TChar>> {
-  size_t operator()(const aapt::BasicStringPiece<TChar>& str) const {
+struct hash<android::BasicStringPiece<TChar>> {
+  size_t operator()(const android::BasicStringPiece<TChar>& str) const {
     uint32_t hashCode = android::JenkinsHashMixBytes(
-        0, reinterpret_cast<const uint8_t*>(str.data()),
-        sizeof(TChar) * str.size());
+        0, reinterpret_cast<const uint8_t*>(str.data()), sizeof(TChar) * str.size());
     return static_cast<size_t>(hashCode);
   }
 };
 
 }  // namespace std
 
-#endif  // AAPT_STRING_PIECE_H
+#endif  // ANDROIDFW_STRING_PIECE_H
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
new file mode 100644
index 0000000..5266d09
--- /dev/null
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <cstdlib>
+#include <memory>
+
+#include "android-base/macros.h"
+
+namespace android {
+namespace util {
+
+/**
+ * Makes a std::unique_ptr<> with the template parameter inferred by the
+ * compiler.
+ * This will be present in C++14 and can be removed then.
+ */
+template <typename T, class... Args>
+std::unique_ptr<T> make_unique(Args&&... args) {
+  return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
+}
+
+// Based on std::unique_ptr, but uses free() to release malloc'ed memory
+// without incurring the size increase of holding on to a custom deleter.
+template <typename T>
+class unique_cptr {
+ public:
+  using pointer = typename std::add_pointer<T>::type;
+
+  constexpr unique_cptr() : ptr_(nullptr) {}
+  constexpr unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
+  explicit unique_cptr(pointer ptr) : ptr_(ptr) {}
+  unique_cptr(unique_cptr&& o) : ptr_(o.ptr_) { o.ptr_ = nullptr; }
+
+  ~unique_cptr() { std::free(reinterpret_cast<void*>(ptr_)); }
+
+  inline unique_cptr& operator=(unique_cptr&& o) {
+    if (&o == this) {
+      return *this;
+    }
+
+    std::free(reinterpret_cast<void*>(ptr_));
+    ptr_ = o.ptr_;
+    o.ptr_ = nullptr;
+    return *this;
+  }
+
+  inline unique_cptr& operator=(std::nullptr_t) {
+    std::free(reinterpret_cast<void*>(ptr_));
+    ptr_ = nullptr;
+    return *this;
+  }
+
+  pointer release() {
+    pointer result = ptr_;
+    ptr_ = nullptr;
+    return result;
+  }
+
+  inline pointer get() const { return ptr_; }
+
+  void reset(pointer ptr = pointer()) {
+    if (ptr == ptr_) {
+      return;
+    }
+
+    pointer old_ptr = ptr_;
+    ptr_ = ptr;
+    std::free(reinterpret_cast<void*>(old_ptr));
+  }
+
+  inline void swap(unique_cptr& o) { std::swap(ptr_, o.ptr_); }
+
+  inline explicit operator bool() const { return ptr_ != nullptr; }
+
+  inline typename std::add_lvalue_reference<T>::type operator*() const { return *ptr_; }
+
+  inline pointer operator->() const { return ptr_; }
+
+  inline bool operator==(const unique_cptr& o) const { return ptr_ == o.ptr_; }
+
+  inline bool operator==(std::nullptr_t) const { return ptr_ == nullptr; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(unique_cptr);
+
+  pointer ptr_;
+};
+
+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_id(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;
+}
+
+}  // namespace util
+}  // namespace android
+
+#endif /* UTIL_H_ */
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index d91a133..650f813 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -21,22 +21,32 @@
 LOCAL_PATH:= $(call my-dir)
 
 testFiles := \
+    ApkAssets_test.cpp \
     AppAsLib_test.cpp \
     Asset_test.cpp \
+    AssetManager2_test.cpp \
     AttributeFinder_test.cpp \
     AttributeResolution_test.cpp \
     ByteBucketArray_test.cpp \
     Config_test.cpp \
     ConfigLocale_test.cpp \
     Idmap_test.cpp \
-    Main.cpp \
+    LoadedArsc_test.cpp \
     ResTable_test.cpp \
     Split_test.cpp \
+    StringPiece_test.cpp \
     TestHelpers.cpp \
+    TestMain.cpp \
     Theme_test.cpp \
     TypeWrappers_test.cpp \
     ZipUtils_test.cpp
 
+benchmarkFiles := \
+    AssetManager2_bench.cpp \
+    BenchMain.cpp \
+    TestHelpers.cpp \
+    Theme_bench.cpp
+
 androidfw_test_cflags := \
     -Wall \
     -Werror \
@@ -89,5 +99,25 @@
 LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
 
 include $(BUILD_NATIVE_TEST)
+
+# ==========================================================
+# Build the device benchmarks: libandroidfw_benchmarks
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libandroidfw_benchmarks
+LOCAL_CFLAGS := $(androidfw_test_cflags)
+LOCAL_SRC_FILES := $(benchmarkFiles)
+LOCAL_STATIC_LIBRARIES := \
+    libgoogle-benchmark
+LOCAL_SHARED_LIBRARIES := \
+    libandroidfw \
+    libbase \
+    libcutils \
+    libutils \
+    libziparchive
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
+
+include $(BUILD_NATIVE_TEST)
 endif # Not SDK_ONLY
 
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
new file mode 100644
index 0000000..3a1fc8f
--- /dev/null
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/ApkAssets.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+
+using com::android::basic::R;
+
+namespace android {
+
+TEST(ApkAssetsTest, LoadApk) {
+  std::unique_ptr<ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+  ASSERT_NE(nullptr, loaded_apk);
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
+}
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
new file mode 100644
index 0000000..9ff9478
--- /dev/null
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ */
+
+#include "benchmark/benchmark.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace basic = com::android::basic;
+namespace app = com::android::app;
+
+namespace android {
+
+constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
+
+static void BM_AssetManagerLoadAssets(benchmark::State& state) {
+  std::string path = GetTestDataPath() + "/basic/basic.apk";
+  while (state.KeepRunning()) {
+    std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
+    AssetManager2 assets;
+    assets.SetApkAssets({apk.get()});
+  }
+}
+BENCHMARK(BM_AssetManagerLoadAssets);
+
+static void BM_AssetManagerLoadAssetsOld(benchmark::State& state) {
+  String8 path((GetTestDataPath() + "/basic/basic.apk").data());
+  while (state.KeepRunning()) {
+    AssetManager assets;
+    assets.addAssetPath(path, nullptr /* cookie */, false /* appAsLib */,
+                        false /* isSystemAsset */);
+
+    // Force creation.
+    assets.getResources(true);
+  }
+}
+BENCHMARK(BM_AssetManagerLoadAssetsOld);
+
+static void BM_AssetManagerLoadFrameworkAssets(benchmark::State& state) {
+  std::string path = kFrameworkPath;
+  while (state.KeepRunning()) {
+    std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
+    AssetManager2 assets;
+    assets.SetApkAssets({apk.get()});
+  }
+}
+BENCHMARK(BM_AssetManagerLoadFrameworkAssets);
+
+static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) {
+  String8 path(kFrameworkPath);
+  while (state.KeepRunning()) {
+    AssetManager assets;
+    assets.addAssetPath(path, nullptr /* cookie */, false /* appAsLib */,
+                        false /* isSystemAsset */);
+
+    // Force creation.
+    assets.getResources(true);
+  }
+}
+BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
+
+static void BM_AssetManagerGetResource(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    assets.GetResource(basic::R::integer::number1, false /* may_be_bag */,
+                       0u /* density_override */, &value, &selected_config, &flags);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResource);
+
+static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8((GetTestDataPath() + "/basic/basic.apk").data()),
+                           nullptr /* cookie */, false /* appAsLib */,
+                           false /* isSystemAssets */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  const ResTable& table = assets.getResources(true);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    table.getResource(basic::R::integer::number1, &value, false /* may_be_bag */,
+                      0u /* density_override */, &flags, &selected_config);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResourceOld);
+
+constexpr static const uint32_t kStringOkId = 0x0104000au;
+
+static void BM_AssetManagerGetResourceFrameworkLocale(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  memcpy(config.language, "fr", 2);
+  assets.SetConfiguration(config);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    assets.GetResource(kStringOkId, false /* may_be_bag */, 0u /* density_override */, &value,
+                       &selected_config, &flags);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResourceFrameworkLocale);
+
+static void BM_AssetManagerGetResourceFrameworkLocaleOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8((GetTestDataPath() + "/basic/basic.apk").data()),
+                           nullptr /* cookie */, false /* appAsLib */,
+                           false /* isSystemAssets */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  memcpy(config.language, "fr", 2);
+  assets.setConfiguration(config, nullptr);
+
+  const ResTable& table = assets.getResources(true);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    table.getResource(kStringOkId, &value, false /* may_be_bag */, 0u /* density_override */,
+                      &flags, &selected_config);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResourceFrameworkLocaleOld);
+
+static void BM_AssetManagerGetBag(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  while (state.KeepRunning()) {
+    const ResolvedBag* bag = assets.GetBag(app::R::style::StyleTwo);
+    const auto bag_end = end(bag);
+    for (auto iter = begin(bag); iter != bag_end; ++iter) {
+      uint32_t key = iter->key;
+      Res_value value = iter->value;
+      benchmark::DoNotOptimize(key);
+      benchmark::DoNotOptimize(value);
+    }
+  }
+}
+BENCHMARK(BM_AssetManagerGetBag);
+
+static void BM_AssetManagerGetBagOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8((GetTestDataPath() + "/styles/styles.apk").data()),
+                           nullptr /* cookie */, false /* appAsLib */,
+                           false /* isSystemAssets */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  const ResTable& table = assets.getResources(true);
+
+  while (state.KeepRunning()) {
+    const ResTable::bag_entry* bag_begin;
+    const ssize_t N = table.lockBag(app::R::style::StyleTwo, &bag_begin);
+    const ResTable::bag_entry* const bag_end = bag_begin + N;
+    for (auto iter = bag_begin; iter != bag_end; ++iter) {
+      uint32_t key = iter->map.name.ident;
+      Res_value value = iter->map.value;
+      benchmark::DoNotOptimize(key);
+      benchmark::DoNotOptimize(value);
+    }
+    table.unlockBag(bag_begin);
+  }
+}
+BENCHMARK(BM_AssetManagerGetBagOld);
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
new file mode 100644
index 0000000..39c5381
--- /dev/null
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/AssetManager2.h"
+#include "androidfw/AssetManager.h"
+
+#include "android-base/logging.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace basic = com::android::basic;
+namespace app = com::android::app;
+
+namespace android {
+
+class AssetManager2Test : public ::testing::Test {
+ public:
+  void SetUp() override {
+    basic_assets_ = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+    ASSERT_NE(nullptr, basic_assets_);
+
+    basic_de_fr_assets_ = ApkAssets::Load(GetTestDataPath() + "/basic/basic_de_fr.apk");
+    ASSERT_NE(nullptr, basic_de_fr_assets_);
+
+    style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+    ASSERT_NE(nullptr, style_assets_);
+  }
+
+ protected:
+  std::unique_ptr<ApkAssets> basic_assets_;
+  std::unique_ptr<ApkAssets> basic_de_fr_assets_;
+  std::unique_ptr<ApkAssets> style_assets_;
+};
+
+TEST_F(AssetManager2Test, FindsResourcesFromSingleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  // Came from our ApkAssets.
+  EXPECT_EQ(0, cookie);
+
+  // It is the default config.
+  EXPECT_EQ(0, selected_config.language[0]);
+  EXPECT_EQ(0, selected_config.language[1]);
+
+  // It is a string.
+  EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+}
+
+TEST_F(AssetManager2Test, FindsResourcesFromMultipleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  // Came from our de_fr ApkAssets.
+  EXPECT_EQ(1, cookie);
+
+  // The configuration is german.
+  EXPECT_EQ('d', selected_config.language[0]);
+  EXPECT_EQ('e', selected_config.language[1]);
+
+  // It is a string.
+  EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+}
+
+TEST_F(AssetManager2Test, FindsBagResourcesFromSingleApkAssets) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  const ResolvedBag* bag = assetmanager.GetBag(basic::R::array::integerArray1);
+  ASSERT_NE(nullptr, bag);
+  ASSERT_EQ(3u, bag->entry_count);
+
+  EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[0].value.dataType);
+  EXPECT_EQ(1u, bag->entries[0].value.data);
+  EXPECT_EQ(0, bag->entries[0].cookie);
+
+  EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[1].value.dataType);
+  EXPECT_EQ(2u, bag->entries[1].value.data);
+  EXPECT_EQ(0, bag->entries[1].cookie);
+
+  EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[2].value.dataType);
+  EXPECT_EQ(3u, bag->entries[2].value.data);
+  EXPECT_EQ(0, bag->entries[2].cookie);
+}
+
+TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  const ResolvedBag* bag_one = assetmanager.GetBag(app::R::style::StyleOne);
+  ASSERT_NE(nullptr, bag_one);
+  ASSERT_EQ(2u, bag_one->entry_count);
+
+  EXPECT_EQ(app::R::attr::attr_one, bag_one->entries[0].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[0].value.dataType);
+  EXPECT_EQ(1u, bag_one->entries[0].value.data);
+  EXPECT_EQ(0, bag_one->entries[0].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_two, bag_one->entries[1].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[1].value.dataType);
+  EXPECT_EQ(2u, bag_one->entries[1].value.data);
+  EXPECT_EQ(0, bag_one->entries[1].cookie);
+
+  const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
+  ASSERT_NE(nullptr, bag_two);
+  ASSERT_EQ(5u, bag_two->entry_count);
+
+  // attr_one is inherited from StyleOne.
+  EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[0].value.dataType);
+  EXPECT_EQ(1u, bag_two->entries[0].value.data);
+  EXPECT_EQ(0, bag_two->entries[0].cookie);
+
+  // attr_two should be overridden from StyleOne by StyleTwo.
+  EXPECT_EQ(app::R::attr::attr_two, bag_two->entries[1].key);
+  EXPECT_EQ(Res_value::TYPE_STRING, bag_two->entries[1].value.dataType);
+  EXPECT_EQ(0, bag_two->entries[1].cookie);
+  EXPECT_EQ(std::string("string"), GetStringFromPool(assetmanager.GetStringPoolForCookie(0),
+                                                     bag_two->entries[1].value.data));
+
+  // The rest are new attributes.
+
+  EXPECT_EQ(app::R::attr::attr_three, bag_two->entries[2].key);
+  EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, bag_two->entries[2].value.dataType);
+  EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[2].value.data);
+  EXPECT_EQ(0, bag_two->entries[2].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_five, bag_two->entries[3].key);
+  EXPECT_EQ(Res_value::TYPE_REFERENCE, bag_two->entries[3].value.dataType);
+  EXPECT_EQ(app::R::string::string_one, bag_two->entries[3].value.data);
+  EXPECT_EQ(0, bag_two->entries[3].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[4].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType);
+  EXPECT_EQ(3u, bag_two->entries[4].value.data);
+  EXPECT_EQ(0, bag_two->entries[4].cookie);
+}
+
+TEST_F(AssetManager2Test, FindsBagResourcesFromMultipleApkAssets) {}
+
+TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
+
+TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 7550517..1ff2ed4 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -205,4 +205,5 @@
   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
 }
 
-}  // namespace android
+} // namespace android
+
diff --git a/libs/androidfw/tests/BenchMain.cpp b/libs/androidfw/tests/BenchMain.cpp
new file mode 100644
index 0000000..105c5f9
--- /dev/null
+++ b/libs/androidfw/tests/BenchMain.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include "benchmark/benchmark.h"
+
+#include "TestHelpers.h"
+
+int main(int argc, char** argv) {
+  ::benchmark::Initialize(&argc, argv);
+  ::android::InitializeTest(&argc, argv);
+
+  std::cerr << "using --testdata=" << ::android::GetTestDataPath() << "\n";
+
+  size_t result = ::benchmark::RunSpecifiedBenchmarks();
+  return result == 0 ? 1 : 0;
+}
diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp
index 778c7bf..3e5aca7 100644
--- a/libs/androidfw/tests/Config_test.cpp
+++ b/libs/androidfw/tests/Config_test.cpp
@@ -182,4 +182,24 @@
   EXPECT_TRUE(targetConfigC.isBetterThan(targetConfigB, &deviceConfig));
 }
 
+TEST(ConfigTest, ScreenIsWideGamut) {
+  ResTable_config defaultConfig;
+  memset(&defaultConfig, 0, sizeof(defaultConfig));
+
+  ResTable_config wideGamutConfig = defaultConfig;
+  wideGamutConfig.colorimetry = ResTable_config::WIDE_COLOR_GAMUT_YES;
+
+  EXPECT_EQ(defaultConfig.diff(wideGamutConfig), ResTable_config::CONFIG_COLORIMETRY);
+}
+
+TEST(ConfigTest, ScreenIsHdr) {
+  ResTable_config defaultConfig;
+  memset(&defaultConfig, 0, sizeof(defaultConfig));
+
+  ResTable_config hdrConfig = defaultConfig;
+  hdrConfig.colorimetry = ResTable_config::HDR_YES;
+
+  EXPECT_EQ(defaultConfig.diff(hdrConfig), ResTable_config::CONFIG_COLORIMETRY);
+}
+
 }  // namespace android.
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
new file mode 100644
index 0000000..47b3894
--- /dev/null
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/LoadedArsc.h"
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace app = com::android::app;
+namespace basic = com::android::basic;
+
+namespace android {
+
+TEST(LoadedArscTest, LoadSinglePackageArsc) {
+  base::ScopedLogSeverity _log(base::LogSeverity::DEBUG);
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
+                                      &contents));
+
+  std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.sdkVersion = 24;
+
+  LoadedArsc::Entry entry;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ASSERT_TRUE(
+      loaded_arsc->FindEntry(app::R::string::string_one, config, &entry, &selected_config, &flags));
+  ASSERT_NE(nullptr, entry.entry);
+}
+
+TEST(LoadedArscTest, FindDefaultEntry) {
+  base::ScopedLogSeverity _log(base::LogSeverity::DEBUG);
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+  std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  LoadedArsc::Entry entry;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry,
+                                     &selected_config, &flags));
+  ASSERT_NE(nullptr, entry.entry);
+}
+
+// structs with size fields (like Res_value, ResTable_entry) should be
+// backwards and forwards compatible (aka checking the size field against
+// sizeof(Res_value) might not be backwards compatible.
+TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Main.cpp b/libs/androidfw/tests/Main.cpp
deleted file mode 100644
index 6a50691..0000000
--- a/libs/androidfw/tests/Main.cpp
+++ /dev/null
@@ -1,69 +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.
- */
-
-#include <libgen.h>
-
-#include <iostream>
-#include <memory>
-#include <string>
-
-#include "android-base/file.h"
-#include "android-base/strings.h"
-#include "gtest/gtest.h"
-
-#include "TestHelpers.h"
-
-// Extract the directory of the current executable path.
-static std::string GetExecutableDir() {
-  const std::string path = android::base::GetExecutablePath();
-  std::unique_ptr<char, decltype(&std::free)> mutable_path = {
-      strdup(path.c_str()), std::free};
-  std::string executable_dir = dirname(mutable_path.get());
-  return executable_dir;
-}
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-
-  // Set the default test data path to be the executable path directory.
-  android::SetTestDataPath(GetExecutableDir());
-
-  const char* command = argv[0];
-  ++argv;
-  --argc;
-
-  while (argc > 0) {
-    const std::string arg = *argv;
-    if (android::base::StartsWith(arg, "--testdata=")) {
-      android::SetTestDataPath(arg.substr(strlen("--testdata=")));
-    } else if (arg == "-h" || arg == "--help") {
-      std::cerr
-          << "\nAdditional options specific to this test:\n"
-             "  --testdata=[PATH]\n"
-             "      Specify the location of test data used within the tests.\n";
-      return 1;
-    } else {
-      std::cerr << command << ": Unrecognized argument '" << *argv << "'.\n";
-      return 1;
-    }
-
-    --argc;
-    ++argv;
-  }
-
-  std::cerr << "using --testdata=" << android::GetTestDataPath() << "\n";
-  return RUN_ALL_TESTS();
-}
diff --git a/tools/aapt2/util/StringPiece_test.cpp b/libs/androidfw/tests/StringPiece_test.cpp
similarity index 96%
rename from tools/aapt2/util/StringPiece_test.cpp
rename to libs/androidfw/tests/StringPiece_test.cpp
index 048961d..316a5c1 100644
--- a/tools/aapt2/util/StringPiece_test.cpp
+++ b/libs/androidfw/tests/StringPiece_test.cpp
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
 
 #include <algorithm>
 #include <string>
 #include <vector>
 
-#include "test/Test.h"
+#include "TestHelpers.h"
 
-namespace aapt {
+namespace android {
 
 TEST(StringPieceTest, CompareNonNullTerminatedPiece) {
   StringPiece a("hello world", 5);
@@ -92,4 +92,4 @@
   EXPECT_FALSE(text16.contains(long_needle16));
 }
 
-}  // namespace aapt
+}  // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 2c834b1..1e763a5 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -16,15 +16,51 @@
 
 #include "TestHelpers.h"
 
+#include <libgen.h>
 #include <unistd.h>
 
+#include <memory>
+#include <string>
+
+#include "android-base/file.h"
 #include "android-base/logging.h"
+#include "android-base/strings.h"
 #include "ziparchive/zip_archive.h"
 
 namespace android {
 
 static std::string sTestDataPath;
 
+// Extract the directory of the current executable path.
+static std::string GetExecutableDir() {
+  const std::string path = base::GetExecutablePath();
+  std::unique_ptr<char, decltype(&std::free)> mutable_path = {strdup(path.c_str()), std::free};
+  std::string executable_dir = dirname(mutable_path.get());
+  return executable_dir;
+}
+
+void InitializeTest(int* argc, char** argv) {
+  // Set the default test data path to be the executable path directory.
+  SetTestDataPath(GetExecutableDir());
+
+  for (int i = 1; i < *argc; i++) {
+    const std::string arg = argv[i];
+    if (base::StartsWith(arg, "--testdata=")) {
+      SetTestDataPath(arg.substr(strlen("--testdata=")));
+      for (int j = i; j != *argc; j++) {
+        argv[j] = argv[j + 1];
+      }
+      --(*argc);
+      --i;
+    } else if (arg == "-h" || arg == "--help") {
+      std::cerr << "\nAdditional options specific to this test:\n"
+                   "  --testdata=[PATH]\n"
+                   "      Specify the location of test data used within the tests.\n";
+      exit(1);
+    }
+  }
+}
+
 void SetTestDataPath(const std::string& path) { sTestDataPath = path; }
 
 const std::string& GetTestDataPath() {
@@ -90,4 +126,9 @@
   return ::testing::AssertionSuccess() << actual_str.string();
 }
 
+std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
+  String8 str = pool->string8ObjectAt(idx);
+  return std::string(str.string(), str.length());
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index d9cee22..a11ea84 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -35,6 +35,8 @@
 
 namespace android {
 
+void InitializeTest(int* argc, char** argv);
+
 enum { MAY_NOT_BE_BAG = false };
 
 void SetTestDataPath(const std::string& path);
@@ -56,6 +58,8 @@
 ::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
                                          const char* expected_str);
 
+std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx);
+
 }  // namespace android
 
 #endif  // TEST_HELPERS_H_
diff --git a/libs/androidfw/tests/TestMain.cpp b/libs/androidfw/tests/TestMain.cpp
new file mode 100644
index 0000000..d1c0f60
--- /dev/null
+++ b/libs/androidfw/tests/TestMain.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include "TestHelpers.h"
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ::android::InitializeTest(&argc, argv);
+
+  std::cerr << "using --testdata=" << ::android::GetTestDataPath() << "\n";
+
+  return RUN_ALL_TESTS();
+}
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
new file mode 100644
index 0000000..c471be6
--- /dev/null
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include "benchmark/benchmark.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
+
+namespace android {
+
+constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
+constexpr const static uint32_t kStyleId = 0x01030237u;  // android:style/Theme.Material.Light
+constexpr const static uint32_t kAttrId = 0x01010030u;   // android:attr/colorForeground
+
+static void BM_ThemeApplyStyleFramework(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  while (state.KeepRunning()) {
+    auto theme = assets.NewTheme();
+    theme->ApplyStyle(kStyleId, false /* force */);
+  }
+}
+BENCHMARK(BM_ThemeApplyStyleFramework);
+
+static void BM_ThemeApplyStyleFrameworkOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /* cookie */, false /* appAsLib */,
+                           true /* isSystemAsset */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  const ResTable& res_table = assets.getResources(true);
+
+  while (state.KeepRunning()) {
+    std::unique_ptr<ResTable::Theme> theme{new ResTable::Theme(res_table)};
+    theme->applyStyle(kStyleId, false /* force */);
+  }
+}
+BENCHMARK(BM_ThemeApplyStyleFrameworkOld);
+
+static void BM_ThemeGetAttribute(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  auto theme = assets.NewTheme();
+  theme->ApplyStyle(kStyleId, false /* force */);
+
+  Res_value value;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    theme->GetAttribute(kAttrId, &value, &flags);
+  }
+}
+BENCHMARK(BM_ThemeGetAttribute);
+
+static void BM_ThemeGetAttributeOld(benchmark::State& state) {
+  AssetManager assets;
+  assets.addAssetPath(String8(kFrameworkPath), nullptr /* cookie */, false /* appAsLib */,
+                      true /* isSystemAsset */);
+  const ResTable& res_table = assets.getResources(true);
+  std::unique_ptr<ResTable::Theme> theme{new ResTable::Theme(res_table)};
+  theme->applyStyle(kStyleId, false /* force */);
+
+  Res_value value;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    theme->getAttribute(kAttrId, &value, &flags);
+  }
+}
+BENCHMARK(BM_ThemeGetAttributeOld);
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 3774657..c0011b6d 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,59 +14,221 @@
  * limitations under the License.
  */
 
-#include "androidfw/ResourceTypes.h"
+#include "androidfw/AssetManager2.h"
 
-#include "utils/String16.h"
-#include "utils/String8.h"
+#include "android-base/logging.h"
 
 #include "TestHelpers.h"
-#include "data/app/R.h"
-#include "data/system/R.h"
+#include "data/styles/R.h"
 
 namespace app = com::android::app;
 
 namespace android {
 
-/**
- * TODO(adamlesinski): Enable when fixed.
- */
-TEST(ThemeTest, DISABLED_shouldCopyThemeFromDifferentResTable) {
-  ResTable table;
+class ThemeTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+    ASSERT_NE(nullptr, style_assets_);
+  }
 
-  std::string system_contents;
-  ASSERT_TRUE(ReadFileFromZipToString("/system/system.apk", "resources.arsc",
-                                      &system_contents));
-  ASSERT_EQ(NO_ERROR,
-            table.add(system_contents.data(), system_contents.size()));
+ protected:
+  std::unique_ptr<ApkAssets> style_assets_;
+};
 
-  std::string app_contents;
-  ASSERT_TRUE(ReadFileFromZipToString("/basic/basic.apk", "resources.arsc",
-                                      &app_contents));
-  ASSERT_EQ(NO_ERROR, table.add(app_contents.data(), app_contents.size()));
+TEST_F(ThemeTest, EmptyTheme) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
 
-  ResTable::Theme theme1(table);
-  ASSERT_EQ(NO_ERROR, theme1.applyStyle(app::R::style::Theme_One));
-  Res_value val;
-  ASSERT_GE(theme1.getAttribute(android::R::attr::background, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
-  ASSERT_EQ(uint32_t(0xffff0000), val.data);
-  ASSERT_GE(theme1.getAttribute(app::R::attr::number, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-  ASSERT_EQ(uint32_t(1), val.data);
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  EXPECT_EQ(0u, theme->GetChangingConfigurations());
+  EXPECT_EQ(&assetmanager, theme->GetAssetManager());
 
-  ResTable table2;
-  ASSERT_EQ(NO_ERROR,
-            table2.add(system_contents.data(), system_contents.size()));
-  ASSERT_EQ(NO_ERROR, table2.add(app_contents.data(), app_contents.size()));
+  Res_value value;
+  uint32_t flags;
+  EXPECT_EQ(kInvalidCookie, theme->GetAttribute(app::R::attr::attr_one, &value, &flags));
+}
 
-  ResTable::Theme theme2(table2);
-  ASSERT_EQ(NO_ERROR, theme2.setTo(theme1));
-  ASSERT_GE(theme2.getAttribute(android::R::attr::background, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
-  ASSERT_EQ(uint32_t(0xffff0000), val.data);
-  ASSERT_GE(theme2.getAttribute(app::R::attr::number, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-  ASSERT_EQ(uint32_t(1), val.data);
+TEST_F(ThemeTest, SingleThemeNoParent) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(2u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, SingleThemeWithParent) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+  EXPECT_EQ(0, cookie);
+  EXPECT_EQ(std::string("string"),
+            GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value.data));
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // This attribute should point to an attr_indirect, so the result should be 3.
+  cookie = theme->GetAttribute(app::R::attr::attr_three, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(3u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  // attr_one is still here from the base.
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the new attr_six
+  cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(6u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the old attr_five (force=true was not used).
+  cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+  EXPECT_EQ(app::R::string::string_one, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  // attr_one is still here from the base.
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the new attr_six
+  cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(6u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the new attr_five (force=true was used).
+  cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(5u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, CopyThemeSameAssetManager) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
+  ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  // attr_one is still here from the base.
+  cookie = theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // attr_six is not here.
+  EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags));
+
+  std::unique_ptr<Theme> theme_two = assetmanager.NewTheme();
+  ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
+
+  // Copy the theme to theme_one.
+  ASSERT_TRUE(theme_one->SetTo(*theme_two));
+
+  // Clear theme_two to make sure we test that there WAS a copy.
+  theme_two->Clear();
+
+  // attr_one is now not here.
+  EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+
+  // attr_six is now here because it was copied.
+  cookie = theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(6u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, FailToCopyThemeWithDifferentAssetManager) {
+  AssetManager2 assetmanager_one;
+  assetmanager_one.SetApkAssets({style_assets_.get()});
+
+  AssetManager2 assetmanager_two;
+  assetmanager_two.SetApkAssets({style_assets_.get()});
+
+  auto theme_one = assetmanager_one.NewTheme();
+  ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
+
+  auto theme_two = assetmanager_two.NewTheme();
+  ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
+
+  EXPECT_FALSE(theme_one->SetTo(*theme_two));
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 4127aa0..68527c7 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -32,6 +32,7 @@
       attr_four = 0x7f010003u,
       attr_five = 0x7f010004u,
       attr_indirect = 0x7f010005u,
+      attr_six = 0x7f010006u,
     };
   };
 
@@ -45,6 +46,7 @@
     enum : uint32_t {
       StyleOne = 0x7f020000u,
       StyleTwo = 0x7f020001u,
+      StyleThree = 0x7f020002u,
     };
   };
 };
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index 70c54f6..da592f8 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -39,6 +39,7 @@
     <public type="style" name="StyleOne" id="0x7f020000" />
     <style name="StyleOne">
         <item name="attr_one">1</item>
+        <item name="attr_two">2</item>
     </style>
 
     <public type="style" name="StyleTwo" id="0x7f020001" />
@@ -48,5 +49,14 @@
         <item name="attr_three">?attr/attr_indirect</item>
         <item name="attr_five">@string/string_one</item>
     </style>
+    
+    <public type="attr" name="attr_six" id="0x7f010006" />
+    <attr name="attr_six" />
+    
+    <public type="style" name="StyleThree" id="0x7f020002" />
+    <style name="StyleThree">
+        <item name="attr_six">6</item>
+        <item name="attr_five">5</item>
+    </style>
 
 </resources>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index 6064c48..d4ccb83 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 3e8e8a1..0ae50e9 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -131,7 +131,7 @@
                         mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
 
     static const mat4 identityMatrix;
-    updateLayer(false, identityMatrix.data);
+    updateLayer(false, GL_NONE, identityMatrix.data);
 
     VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
     vkLayer->updateTexture();
@@ -139,26 +139,20 @@
 
 void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
         const float* textureTransform) {
-    LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
-                        "updateLayer non GL backend %x, GL %x, VK %x",
-                        mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
-
-    updateLayer(forceFilter, textureTransform);
-
-    GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
-    if (renderTarget != glLayer->getRenderTarget()) {
-        glLayer->setRenderTarget(renderTarget);
-        glLayer->bindTexture();
-        glLayer->setFilter(GL_NEAREST, false, true);
-        glLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
-    }
-}
-
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
     mLayer->getTexTransform().load(textureTransform);
+
+    if (mLayer->getApi() == Layer::Api::OpenGL) {
+        GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
+        if (renderTarget != glLayer->getRenderTarget()) {
+            glLayer->setRenderTarget(renderTarget);
+            glLayer->bindTexture();
+            glLayer->setFilter(GL_NEAREST, false, true);
+            glLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
+        }
+    }
 }
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index ead8314..3814be2 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -114,7 +114,6 @@
 
     void doUpdateTexImage();
     void doUpdateVkTexImage();
-    void updateLayer(bool forceFilter, const float* textureTransform);
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index a53a55a..1d8b021 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -180,16 +180,18 @@
         }
     }
 
-    if (!backdrop.isEmpty()) {
-        // content node translation to catch up with backdrop
-        float dx = contentDrawBounds.left - backdrop.left;
-        float dy = contentDrawBounds.top - backdrop.top;
+    if (!nodes[1]->nothingToDraw()) {
+        if (!backdrop.isEmpty()) {
+            // content node translation to catch up with backdrop
+            float dx = contentDrawBounds.left - backdrop.left;
+            float dy = contentDrawBounds.top - backdrop.top;
 
-        Rect contentLocalClip = backdrop;
-        contentLocalClip.translate(dx, dy);
-        deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]);
-    } else {
-        deferRenderNode(*nodes[1]);
+            Rect contentLocalClip = backdrop;
+            contentLocalClip.translate(dx, dy);
+            deferRenderNode(-dx, -dy, contentLocalClip, *nodes[1]);
+        } else {
+            deferRenderNode(*nodes[1]);
+        }
     }
 
     // remaining overlay nodes, simply defer
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 0702010..09e34bf 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -222,6 +222,12 @@
     return sRenderPipelineType;
 }
 
+#ifdef HWUI_GLES_WRAP_ENABLED
+void Properties::overrideRenderPipelineType(RenderPipelineType type) {
+    sRenderPipelineType = type;
+}
+#endif
+
 bool Properties::isSkiaEnabled() {
     auto renderType = getRenderPipelineType();
     return RenderPipelineType::SkiaGL == renderType
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index b4a3118..6dc0cb3 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -318,11 +318,15 @@
     // any overhead they add
     static bool filterOutTestOverhead;
 
+    // Used for testing only to change the render pipeline.
+#ifdef HWUI_GLES_WRAP_ENABLED
+    static void overrideRenderPipelineType(RenderPipelineType);
+#endif
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
     static RenderPipelineType sRenderPipelineType;
-
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 6a00379..956f66e 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -17,8 +17,7 @@
 #include "MinikinSkia.h"
 
 #include <log/log.h>
-#include <SkFontDescriptor.h>
-#include <SkFontMgr.h>
+
 #include <SkPaint.h>
 #include <SkTypeface.h>
 
@@ -87,28 +86,6 @@
     return mTtcIndex;
 }
 
-minikin::MinikinFont* MinikinFontSkia::createFontWithVariation(
-        const std::vector<minikin::FontVariation>& variations) const {
-    SkFontMgr::FontParameters params;
-
-    int ttcIndex;
-    SkStreamAsset* stream = mTypeface->openStream(&ttcIndex);
-    LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed");
-
-    params.setCollectionIndex(ttcIndex);
-    std::vector<SkFontMgr::FontParameters::Axis> skAxes;
-    skAxes.resize(variations.size());
-    for (size_t i = 0; i < variations.size(); i++) {
-        skAxes[i].fTag = variations[i].axisTag;
-        skAxes[i].fStyleValue = SkFloatToScalar(variations[i].value);
-    }
-    params.setAxes(skAxes.data(), skAxes.size());
-    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
-    sk_sp<SkTypeface> face(fm->createFromStream(stream, params));
-
-    return new MinikinFontSkia(std::move(face), mFontData, mFontSize, ttcIndex);
-}
-
 uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
     uint32_t flags = paint->getFlags();
     SkPaint::Hinting hinting = paint->getHinting();
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index 249b0cb..3ee916c 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -44,8 +44,6 @@
     const void* GetFontData() const;
     size_t GetFontSize() const;
     int GetFontIndex() const;
-    minikin::MinikinFont* createFontWithVariation(
-            const std::vector<minikin::FontVariation>&) const;
 
     static uint32_t packPaintFlags(const SkPaint* paint);
     static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index b69b0cb..ca43156 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -62,7 +62,7 @@
 Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
-    if (result != nullptr) {
+    if (result != 0) {
         result->fFontCollection = resolvedFace->fFontCollection;
         result->fFontCollection->Ref();
         result->fSkiaStyle = style;
@@ -72,30 +72,10 @@
     return result;
 }
 
-Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
-        const std::vector<minikin::FontVariation>& variations) {
-    Typeface* resolvedFace = Typeface::resolveDefault(src);
-    Typeface* result = new Typeface();
-    if (result != nullptr) {
-        result->fFontCollection =
-                resolvedFace->fFontCollection->createCollectionWithVariation(variations);
-        if (result->fFontCollection == nullptr) {
-            // None of passed axes are supported by this collection.
-            // So we will reuse the same collection with incrementing reference count.
-            result->fFontCollection = resolvedFace->fFontCollection;
-            result->fFontCollection->Ref();
-        }
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
-        result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
-    }
-    return result;
-}
-
 Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
-    if (result != nullptr) {
+    if (result != 0) {
         result->fFontCollection = resolvedFace->fFontCollection;
         result->fFontCollection->Ref();
         result->fSkiaStyle = resolvedFace->fSkiaStyle;
@@ -150,9 +130,9 @@
     sk_sp<SkTypeface> typeface = SkTypeface::MakeFromStream(fontData.release());
     LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", kRobotoFont);
 
+    minikin::FontFamily* family = new minikin::FontFamily();
     minikin::MinikinFont* font = new MinikinFontSkia(std::move(typeface), data, st.st_size, 0);
-    minikin::FontFamily* family = new minikin::FontFamily(
-                 std::vector<minikin::Font>({ minikin::Font(font, minikin::FontStyle()) }));
+    family->addFont(font);
     font->Unref();
 
     std::vector<minikin::FontFamily*> typefaces = { family };
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index 4392ebc..1be630c 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -43,9 +43,6 @@
 
     static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
 
-    static Typeface* createFromTypefaceWithVariation(Typeface* src,
-            const std::vector<minikin::FontVariation>& variations);
-
     static Typeface* createWeightAlias(Typeface* src, int baseweight);
 
     static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families);
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 419c8a9..6ca8d8b 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -19,7 +19,6 @@
 #include "RenderNode.h"
 #include "SkClipStack.h"
 #include <private/hwui/DrawGlInfo.h>
-#include <SkPath.h>
 #include <GrContext.h>
 
 namespace android {
@@ -76,9 +75,7 @@
 
     //apply a simple clip with a scissor or a complex clip with a stencil
     SkRegion clipRegion;
-    SkPath path;
-    canvas->getClipStack()->asPath(&path);
-    clipRegion.setPath(path, SkRegion(ibounds));
+    canvas->temporary_internal_getRgnClip(&clipRegion);
     if (CC_UNLIKELY(clipRegion.isComplex())) {
         //It is only a temporary solution to use a scissor to draw the stencil.
         //There is a bug 31489986 to implement efficiently non-rectangular clips.
diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp
index d935382..8a0b64b 100644
--- a/libs/hwui/tests/common/LeakChecker.cpp
+++ b/libs/hwui/tests/common/LeakChecker.cpp
@@ -67,6 +67,12 @@
 }
 
 void LeakChecker::checkForLeaks() {
+    // TODO: Re-enable, disabled to workaround b/34586922
+    if ((true)) {
+        cout << "checkForLeaks disabled, see b/34586922" << endl;
+        return;
+    }
+
     // TODO: Until we can shutdown the RT thread we need to do this in
     // two passes as GetUnreachableMemory has limited insight into
     // thread-local caches so some leaks will not be properly tagged as leaks
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 5f6bcb3..79daa3f 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -21,6 +21,9 @@
 
 #include <renderthread/EglManager.h>
 #include <renderthread/OpenGLPipeline.h>
+#include <pipeline/skia/SkiaOpenGLPipeline.h>
+#include <pipeline/skia/SkiaVulkanPipeline.h>
+#include <renderthread/VulkanManager.h>
 #include <utils/Unicode.h>
 #include <SkClipStack.h>
 
@@ -47,10 +50,24 @@
 }
 
 sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
+        renderthread::RenderThread& renderThread) {
+    android::uirenderer::renderthread::IRenderPipeline* pipeline;
+    if (Properties::getRenderPipelineType() == RenderPipelineType::OpenGL) {
+        pipeline = new renderthread::OpenGLPipeline(renderThread);
+    } else if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        pipeline = new skiapipeline::SkiaOpenGLPipeline(renderThread);
+    } else {
+        pipeline = new skiapipeline::SkiaVulkanPipeline(renderThread);
+    }
+    sp<DeferredLayerUpdater> layerUpdater = pipeline->createTextureLayer();
+    delete pipeline;
+    return layerUpdater;
+}
+
+sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
         renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
         const SkMatrix& transform) {
-    renderthread::OpenGLPipeline pipeline(renderThread);
-    sp<DeferredLayerUpdater> layerUpdater = pipeline.createTextureLayer();
+    sp<DeferredLayerUpdater> layerUpdater = createTextureLayerUpdater(renderThread);
     layerUpdater->backingLayer()->getTransform().load(transform);
     layerUpdater->setSize(width, height);
     layerUpdater->setTransform(&transform);
@@ -111,12 +128,20 @@
 void TestUtils::TestTask::run() {
     // RenderState only valid once RenderThread is running, so queried here
     renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance();
-    renderThread.eglManager().initialize();
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        renderThread.vulkanManager().initialize();
+    } else {
+        renderThread.eglManager().initialize();
+    }
 
     rtCallback(renderThread);
 
-    renderThread.renderState().flush(Caches::FlushMode::Full);
-    renderThread.eglManager().destroy();
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        renderThread.vulkanManager().destroy();
+    } else {
+        renderThread.renderState().flush(Caches::FlushMode::Full);
+        renderThread.eglManager().destroy();
+    }
 }
 
 std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) {
@@ -168,10 +193,9 @@
 }
 
 SkRect TestUtils::getClipBounds(const SkCanvas* canvas) {
-    SkClipStack::BoundsType boundType;
-    SkRect clipBounds;
-    canvas->getClipStack()->getBounds(&clipBounds, &boundType);
-    return clipBounds;
+    SkIRect bounds;
+    (void)canvas->getClipDeviceBounds(&bounds);
+    return SkRect::Make(bounds);
 }
 
 SkRect TestUtils::getLocalClipBounds(const SkCanvas* canvas) {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 80cbb24..8b287de 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -19,6 +19,7 @@
 #include <DeviceInfo.h>
 #include <DisplayList.h>
 #include <Matrix.h>
+#include <Properties.h>
 #include <Rect.h>
 #include <RenderNode.h>
 #include <hwui/Bitmap.h>
@@ -51,6 +52,31 @@
         } else { \
             ADD_FAILURE() << "ClipState not a rect"; \
         }
+
+#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
+    TEST(test_case_name, test_name##_##pipeline) { \
+        RenderPipelineType oldType = Properties::getRenderPipelineType(); \
+        Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
+        functionCall; \
+        Properties::overrideRenderPipelineType(oldType); \
+    };
+
+/**
+ * Like gtests' TEST, but only runs with the OpenGL RenderPipelineType
+ */
+#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+    class test_case_name##_##test_name##_HwuiTest { \
+    public: \
+        static void doTheThing(); \
+    }; \
+    INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \
+            test_case_name##_##test_name##_HwuiTest::doTheThing()) \
+    void test_case_name##_##test_name##_HwuiTest::doTheThing()
+
+#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \
+    INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
+            TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing))
+
 /**
  * Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
  * (for e.g. accessing its RenderState)
@@ -60,9 +86,32 @@
     public: \
         static void doTheThing(renderthread::RenderThread& renderThread); \
     }; \
-    TEST(test_case_name, test_name) { \
-        TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
+    void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+
+/**
+ * Like RENDERTHREAD_TEST, but only runs with the OpenGL RenderPipelineType
+ */
+#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+    class test_case_name##_##test_name##_RenderThreadTest { \
+    public: \
+        static void doTheThing(renderthread::RenderThread& renderThread); \
     }; \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+    void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+
+/**
+ * Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes
+ */
+#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
+    class test_case_name##_##test_name##_RenderThreadTest { \
+    public: \
+        static void doTheThing(renderthread::RenderThread& renderThread); \
+    }; \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
     void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
 
 /**
@@ -137,6 +186,9 @@
     }
 
     static sp<DeferredLayerUpdater> createTextureLayerUpdater(
+            renderthread::RenderThread& renderThread);
+
+    static sp<DeferredLayerUpdater> createTextureLayerUpdater(
             renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
             const SkMatrix& transform);
 
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index d44be7d..9a3b81c 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -80,7 +80,7 @@
             << "Glop(s) expected";
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
     SkPaint strokePaint;
     strokePaint.setStyle(SkPaint::kStroke_Style);
     strokePaint.setStrokeWidth(4);
@@ -113,7 +113,7 @@
     testUnmergedGlopDispatch(renderThread, &ovalOp, textureGlopVerifier);
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
     SkPaint layerPaint;
     layerPaint.setAlpha(128);
     OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
@@ -131,7 +131,7 @@
     return result;
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, offsetFlags) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, offsetFlags) {
     Rect bounds(10, 15, 20, 25);
     SkPaint paint;
     SkPaint aaPaint;
@@ -157,7 +157,7 @@
             << "Expect an offset for non-AA lines.";
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, renderTextWithShadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) {
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
 
@@ -232,7 +232,7 @@
     return c;
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, layerUpdateProperties) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, layerUpdateProperties) {
     for (bool debugOverdraw : { false, true }) {
         for (bool debugLayersUpdates : { false, true }) {
             ScopedProperty<bool> ovdProp(Properties::debugOverdraw, debugOverdraw);
@@ -273,7 +273,7 @@
     }
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, pathTextureSnapping) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTextureSnapping) {
     Rect bounds(10, 15, 20, 25);
     SkPaint paint;
     SkPath path;
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
index 59bd75e..380062a 100644
--- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -23,7 +23,7 @@
 
 const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
-RENDERTHREAD_TEST(BakedOpRenderer, startRepaintLayer_clear) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
     BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, sLightInfo);
     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u);
 
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index d3d80a9..42ba3db 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -46,5 +46,10 @@
 RENDERTHREAD_TEST(CanvasContext, invokeFunctor) {
     TestUtils::MockFunctor functor;
     CanvasContext::invokeFunctor(renderThread, &functor);
-    ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcess);
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        // we currently don't support OpenGL WebViews on the Vulkan backend
+        ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcessNoContext);
+    } else {
+        ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcess);
+    }
 }
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index f1b8882..1ef9dba 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -16,8 +16,8 @@
 
 #include "DeferredLayerUpdater.h"
 #include "GlLayer.h"
+#include "Properties.h"
 
-#include "renderthread/OpenGLPipeline.h"
 #include "tests/common/TestUtils.h"
 
 #include <gtest/gtest.h>
@@ -26,12 +26,10 @@
 using namespace android::uirenderer;
 
 RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
-    renderthread::OpenGLPipeline pipeline(renderThread);
-    sp<DeferredLayerUpdater> layerUpdater = pipeline.createTextureLayer();
+    sp<DeferredLayerUpdater> layerUpdater = TestUtils::createTextureLayerUpdater(renderThread);
     layerUpdater->setSize(100, 100);
     layerUpdater->setBlend(true);
 
-
     // updates are deferred so the backing layer should still be in its default state
     if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
         GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
diff --git a/libs/hwui/tests/unit/DeviceInfoTests.cpp b/libs/hwui/tests/unit/DeviceInfoTests.cpp
index 17236bd..af37938 100644
--- a/libs/hwui/tests/unit/DeviceInfoTests.cpp
+++ b/libs/hwui/tests/unit/DeviceInfoTests.cpp
@@ -17,11 +17,12 @@
 #include <DeviceInfo.h>
 
 #include <gtest/gtest.h>
+#include "tests/common/TestUtils.h"
 
 using namespace android;
 using namespace android::uirenderer;
 
-TEST(DeviceInfo, basic) {
+OPENGL_PIPELINE_TEST(DeviceInfo, basic) {
     // can't assert state before init - another test may have initialized the singleton
     DeviceInfo::initialize();
     const DeviceInfo* di = DeviceInfo::get();
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
index 99080ac..ee20236 100644
--- a/libs/hwui/tests/unit/FontRendererTests.cpp
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -28,7 +28,7 @@
     return true;
 }
 
-RENDERTHREAD_TEST(FontRenderer, renderDropShadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) {
     SkPaint paint;
     paint.setTextSize(10);
     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 71c7516..5a2791c 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -109,7 +109,7 @@
 
 class FailRenderer : public TestRendererBase {};
 
-RENDERTHREAD_TEST(FrameBuilder, simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simple) {
     class SimpleTestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -143,7 +143,7 @@
     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
 }
 
-RENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
     class SimpleStrokeTestRenderer : public TestRendererBase {
     public:
         void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
@@ -171,7 +171,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) {
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -187,7 +187,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleBatching) {
     const int LOOPS = 5;
     class SimpleBatchingTestRenderer : public TestRendererBase {
     public:
@@ -225,7 +225,7 @@
             << "Expect number of ops = 2 * loop count";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, deferRenderNode_translateClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) {
     class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -251,7 +251,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, deferRenderNodeScene) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
     class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -311,16 +311,35 @@
         TestUtils::syncHierarchyPropertiesAndDisplayList(node);
     }
 
-    FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
-            sLightGeometry, Caches::getInstance());
-    frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
+    {
+        FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
+                sLightGeometry, Caches::getInstance());
+        frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
 
-    DeferRenderNodeSceneTestRenderer renderer;
-    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
-    EXPECT_EQ(4, renderer.getIndex());
+        DeferRenderNodeSceneTestRenderer renderer;
+        frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+        EXPECT_EQ(4, renderer.getIndex());
+    }
+
+    for (auto& node : nodes) {
+        EXPECT_FALSE(node->nothingToDraw());
+        node->setStagingDisplayList(nullptr, nullptr);
+        node->destroyHardwareResources(nullptr);
+        EXPECT_TRUE(node->nothingToDraw());
+    }
+
+    {
+        // Validate no crashes if any nodes are missing DisplayLists
+        FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
+                sLightGeometry, Caches::getInstance());
+        frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
+
+        FailRenderer renderer;
+        frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    }
 }
 
-RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_noFbo0) {
     class EmptyNoFbo0TestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -338,7 +357,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_withFbo0) {
     class EmptyWithFbo0TestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -364,7 +383,7 @@
             " but fbo0 update lifecycle should still be observed";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
     class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -394,7 +413,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
     static sk_sp<Bitmap> opaqueBitmap(TestUtils::createBitmap(50, 50,
             SkColorType::kRGB_565_SkColorType));
     static sk_sp<Bitmap> transpBitmap(TestUtils::createBitmap(50, 50,
@@ -437,7 +456,7 @@
     EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clippedMerging) {
     class ClippedMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedBitmapOps(const MergedBakedOpList& opList) override {
@@ -479,7 +498,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, regionClipStopsMerge) {
     class RegionClipStopsMergeTestRenderer : public TestRendererBase {
     public:
         void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
@@ -508,7 +527,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textMerging) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textMerging) {
     class TextMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedTextOps(const MergedBakedOpList& opList) override {
@@ -538,7 +557,7 @@
     EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStrikethrough) {
     const int LOOPS = 5;
     class TextStrikethroughTestRenderer : public TestRendererBase {
     public:
@@ -576,7 +595,7 @@
 static auto styles = {
         SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
 
-RENDERTHREAD_TEST(FrameBuilder, textStyle) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
     class TextStyleTestRenderer : public TestRendererBase {
     public:
         void onMergedTextOps(const MergedBakedOpList& opList) override {
@@ -630,7 +649,7 @@
     EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
     class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
     public:
         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
@@ -664,7 +683,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_combineMatrices) {
     class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
     public:
         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
@@ -696,10 +715,10 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_reject) {
     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
             SkMatrix::MakeTrans(5, 5));
-    if (layerUpdater->backingLayer()->getApi() != Layer::Api::OpenGL) return;
+    EXPECT_EQ(Layer::Api::OpenGL, layerUpdater->backingLayer()->getApi());
 
     GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
     glLayer->setRenderTarget(GL_NONE); // Should be rejected
@@ -717,7 +736,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, functor_reject) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, functor_reject) {
     class FunctorTestRenderer : public TestRendererBase {
     public:
         void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
@@ -742,7 +761,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferColorOp_unbounded) {
     class ColorTestRenderer : public TestRendererBase {
     public:
         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
@@ -767,7 +786,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
 }
 
-TEST(FrameBuilder, renderNode) {
+OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) {
     class RenderNodeTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -814,7 +833,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, clipped) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clipped) {
     class ClippedTestRenderer : public TestRendererBase {
     public:
         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
@@ -840,7 +859,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_simple) {
     class SaveLayerSimpleTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -890,7 +909,7 @@
     EXPECT_EQ(5, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
     /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
      * - startTemporaryLayer2, rect2 endLayer2
      * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
@@ -973,7 +992,7 @@
     EXPECT_EQ(12, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_contentRejection) {
         auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
                 [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -996,7 +1015,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_simple) {
     class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1041,7 +1060,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_round) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_round) {
     class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1075,7 +1094,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
     class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1133,7 +1152,7 @@
             << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
     class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1175,7 +1194,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_reject) {
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         // unclipped savelayer + rect both in area that won't intersect with dirty
@@ -1197,7 +1216,7 @@
  * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
  * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
  */
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) {
     class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
@@ -1262,7 +1281,7 @@
     EXPECT_EQ(13, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_simple) {
     class HwLayerSimpleTestRenderer : public TestRendererBase {
     public:
         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1326,7 +1345,7 @@
     *layerHandle = nullptr;
 }
 
-RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
     /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
      * - startRepaintLayer(child), rect(grey), endLayer
      * - startTemporaryLayer, drawLayer(child), endLayer
@@ -1435,7 +1454,7 @@
 }
 
 
-RENDERTHREAD_TEST(FrameBuilder, buildLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
     class BuildLayerTestRenderer : public TestRendererBase {
     public:
         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1531,7 +1550,7 @@
 
 } // end anonymous namespace
 
-RENDERTHREAD_TEST(FrameBuilder, zReorder) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, zReorder) {
     auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.insertReorderBarrier(true);
@@ -1566,7 +1585,7 @@
     EXPECT_EQ(13, renderer.getIndex());
 };
 
-RENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorder) {
     static const int scrollX = 5;
     static const int scrollY = 10;
     class ProjectionReorderTestRenderer : public TestRendererBase {
@@ -1659,7 +1678,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionHwLayer) {
     static const int scrollX = 5;
     static const int scrollY = 10;
     class ProjectionHwLayerTestRenderer : public TestRendererBase {
@@ -1750,7 +1769,7 @@
     *layerHandle = nullptr;
 }
 
-RENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionChildScroll) {
     static const int scrollX = 500000;
     static const int scrollY = 0;
     class ProjectionChildScrollTestRenderer : public TestRendererBase {
@@ -1817,7 +1836,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) {
     class ShadowTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1850,7 +1869,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowSaveLayer) {
     class ShadowSaveLayerTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -1896,7 +1915,7 @@
     EXPECT_EQ(6, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowHwLayer) {
     class ShadowHwLayerTestRenderer : public TestRendererBase {
     public:
         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1954,7 +1973,7 @@
     *layerHandle = nullptr;
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowLayering) {
     class ShadowLayeringTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1981,7 +2000,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowClipping) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowClipping) {
     class ShadowClippingTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -2041,7 +2060,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
     testProperty([](RenderProperties& properties) {
         properties.setAlpha(0.5f);
         properties.setHasOverlappingRendering(false);
@@ -2050,7 +2069,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropClipping) {
     testProperty([](RenderProperties& properties) {
         properties.setClipToBounds(true);
         properties.setClipBounds(Rect(10, 20, 300, 400));
@@ -2060,7 +2079,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropRevealClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableRevealClip().set(true, 50, 50, 25);
     }, [](const RectOp& op, const BakedOpState& state) {
@@ -2071,7 +2090,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOutlineClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableOutline().setShouldClip(true);
         properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
@@ -2083,7 +2102,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropTransform) {
     testProperty([](RenderProperties& properties) {
         properties.setLeftTopRightBottom(10, 10, 110, 110);
 
@@ -2192,7 +2211,7 @@
     ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         properties.setTranslationX(10); // offset rendering content
@@ -2211,7 +2230,7 @@
                 << "expect drawLayer to be translated as part of being clipped";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         // Translate and rotate the view so that the only visible part is the top left corner of
@@ -2230,7 +2249,7 @@
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         properties.setPivotX(0);
@@ -2244,7 +2263,7 @@
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, clip_replace) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clip_replace) {
     class ClipReplaceTestRenderer : public TestRendererBase {
     public:
         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
@@ -2269,7 +2288,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
     /* R is backward projected on B
                 A
                / \
@@ -2299,7 +2318,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectLast) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) {
     /* R is backward projected on E
                   A
                 / | \
@@ -2331,7 +2350,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderNoReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) {
     /* R is backward projected without receiver
                 A
                / \
@@ -2360,7 +2379,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderParentReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivable) {
     /* R is backward projected on C
                 A
                / \
@@ -2389,7 +2408,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
      auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         drawOrderedNode(&canvas, 0, nullptr); //nodeB
@@ -2412,7 +2431,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectedSibling) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) {
     //TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
     //bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
     //tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
@@ -2445,7 +2464,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectedSibling2) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling2) {
     /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
                 A
                 |
@@ -2478,7 +2497,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
     /* R is backward projected on B
                 A
                 |
@@ -2510,7 +2529,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderTwoReceivables) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables) {
     /* B and G are receivables, R is backward projected
                 A
                / \
@@ -2543,7 +2562,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
     /* B and G are receivables, G is backward projected
                 A
                / \
@@ -2576,7 +2595,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
     /* B and G are receivables, R is backward projected
                 A
                / \
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index ce1db05..caeb6bf 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -116,7 +116,7 @@
     return glop;
 }
 
-RENDERTHREAD_TEST(GlopBuilder, rectSnapTest) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(GlopBuilder, rectSnapTest) {
     RenderState& renderState = renderThread.renderState();
     Caches& caches = Caches::getInstance();
     SkPaint paint;
diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp
index 0ee9647..a3b346f 100644
--- a/libs/hwui/tests/unit/GradientCacheTests.cpp
+++ b/libs/hwui/tests/unit/GradientCacheTests.cpp
@@ -23,7 +23,7 @@
 using namespace android;
 using namespace android::uirenderer;
 
-RENDERTHREAD_TEST(GradientCache, addRemove) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(GradientCache, addRemove) {
     Extensions extensions;
     GradientCache cache(extensions);
     ASSERT_LT(1000u, cache.getMaxSize()) << "Expect non-trivial size";
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 06599dd..6c42ca1 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -29,7 +29,7 @@
 const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
 const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
-RENDERTHREAD_TEST(LeakCheck, saveLayer_overdrawRejection) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayer_overdrawRejection) {
     auto node = TestUtils::createNode(0, 0, 100, 100,
             [](RenderProperties& props, Canvas& canvas) {
         canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
@@ -49,7 +49,7 @@
     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayerUnclipped_simple) {
     auto node = TestUtils::createNode(0, 0, 200, 200,
             [](RenderProperties& props, Canvas& canvas) {
         canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp
index 0881fa2..511d6d2 100644
--- a/libs/hwui/tests/unit/MeshStateTests.cpp
+++ b/libs/hwui/tests/unit/MeshStateTests.cpp
@@ -24,7 +24,7 @@
 using namespace android::uirenderer;
 using namespace testing;
 
-RENDERTHREAD_TEST(MeshState, genOrUpdate) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(MeshState, genOrUpdate) {
     debug::ScopedReplaceDriver<debug::MockGlesDriver> driverRef;
     auto& mockGlDriver = driverRef.get();
     EXPECT_CALL(mockGlDriver, glGenBuffers_(_, _)).WillOnce(SetArgPointee<1>(35));
@@ -33,4 +33,4 @@
 
     GLuint buffer = 0;
     renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, GL_DYNAMIC_DRAW);
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index b7950aa..6cd595a 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -30,7 +30,7 @@
     EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000));
 }
 
-RENDERTHREAD_TEST(OffscreenBuffer, construct) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, construct) {
     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u);
     EXPECT_EQ(49u, layer.viewportWidth);
     EXPECT_EQ(149u, layer.viewportHeight);
@@ -41,7 +41,7 @@
     EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
 }
 
-RENDERTHREAD_TEST(OffscreenBuffer, getTextureCoordinates) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) {
     OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
     EXPECT_EQ(Rect(0, 1, 1, 0),
             layerAligned.getTextureCoordinates());
@@ -51,7 +51,7 @@
             layerUnaligned.getTextureCoordinates());
 }
 
-RENDERTHREAD_TEST(OffscreenBuffer, dirty) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, dirty) {
     OffscreenBuffer buffer(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
     buffer.dirty(Rect(-100, -100, 100, 100));
     EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds());
@@ -65,7 +65,7 @@
             << "pool must read size from Properties";
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, getPutClear) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClear) {
     OffscreenBufferPool pool;
 
     auto layer = pool.get(renderThread.renderState(), 100u, 200u);
@@ -88,7 +88,7 @@
     EXPECT_EQ(0u, pool.getCount());
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, resize) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resize) {
     OffscreenBufferPool pool;
 
     auto layer = pool.get(renderThread.renderState(), 64u, 64u);
@@ -123,7 +123,7 @@
     pool.putOrDelete(layer2);
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, putAndDestroy) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, putAndDestroy) {
     OffscreenBufferPool pool;
     // layer too big to return to the pool
     // Note: this relies on the fact that the pool won't reject based on max texture size
@@ -133,7 +133,7 @@
     EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, clear) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) {
     EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
     OffscreenBufferPool pool;
 
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 4a73383..124f5fa 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -47,7 +47,13 @@
     opValidator(*(dl->getOps()[0]));
 }
 
-TEST(RecordingCanvas, emptyPlayback) {
+// The RecordingCanvas is only ever used by the OpenGL RenderPipeline and never when Skia is in use.
+// Thus, even though many of these test are not directly dependent on the current RenderPipeline, we
+// set them all to be OPENGL_PIPELINE_TESTs in case the underlying code in RecordingCanvas ever
+// changes to require the use of the OPENGL_PIPELINE. Currently the textureLayer test is the only
+// test that requires being an OPENGL_PIPELINE_TEST.
+
+OPENGL_PIPELINE_TEST(RecordingCanvas, emptyPlayback) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.restore();
@@ -55,7 +61,7 @@
     playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
 }
 
-TEST(RecordingCanvas, clipRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, clipRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
@@ -71,7 +77,7 @@
             << "Clip should be serialized once";
 }
 
-TEST(RecordingCanvas, emptyClipRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, emptyClipRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
@@ -82,7 +88,7 @@
     ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
 }
 
-TEST(RecordingCanvas, emptyPaintRejection) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, emptyPaintRejection) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint emptyPaint;
         emptyPaint.setColor(Color::Transparent);
@@ -103,7 +109,7 @@
     EXPECT_EQ(0u, dl->getOps().size()) << "Op should be rejected";
 }
 
-TEST(RecordingCanvas, drawArc) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawArc) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
         canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint());
@@ -119,7 +125,7 @@
     EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
 }
 
-TEST(RecordingCanvas, drawLines) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawLines) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
@@ -136,7 +142,7 @@
             << "unmapped bounds must be size of line, and not outset for stroke width";
 }
 
-TEST(RecordingCanvas, drawRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.drawRect(10, 20, 90, 180, SkPaint());
     });
@@ -148,7 +154,7 @@
     EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
 }
 
-TEST(RecordingCanvas, drawRoundRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRoundRect) {
     // Round case - stays rounded
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.drawRoundRect(0, 0, 100, 100, 10, 10, SkPaint());
@@ -165,7 +171,7 @@
         << "Non-rounded rects should be converted";
 }
 
-TEST(RecordingCanvas, drawGlyphs) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -186,7 +192,7 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -218,7 +224,7 @@
     EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
 }
 
-TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -248,7 +254,7 @@
     ASSERT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, drawColor) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawColor) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawColor(Color::Black, SkBlendMode::kSrcOver);
     });
@@ -260,7 +266,7 @@
     EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds";
 }
 
-TEST(RecordingCanvas, backgroundAndImage) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, backgroundAndImage) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
         SkPaint paint;
@@ -312,7 +318,7 @@
     ASSERT_EQ(2, count);
 }
 
-RENDERTHREAD_TEST(RecordingCanvas, textureLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(RecordingCanvas, textureLayer) {
     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
             SkMatrix::MakeTrans(5, 5));
 
@@ -327,7 +333,7 @@
     });
 }
 
-TEST(RecordingCanvas, saveLayer_simple) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simple) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(10, 20, 190, 180, SkPaint());
@@ -361,7 +367,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rounding) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rounding) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
             canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer);
             canvas.drawRect(20, 20, 80, 80, SkPaint());
@@ -391,7 +397,7 @@
         EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_missingRestore) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_missingRestore) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 200, 200, SkPaint());
@@ -406,7 +412,7 @@
     EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer";
 }
 
-TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
         canvas.drawRect(10, 20, 190, 180, SkPaint());
@@ -438,7 +444,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_addClipFlag) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_addClipFlag) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(10, 20, 190, 180, SkClipOp::kIntersect);
@@ -457,7 +463,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_viewportCrop) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_viewportCrop) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // shouldn't matter, since saveLayer will clip to its bounds
         canvas.clipRect(-1000, -1000, 1000, 1000, SkClipOp::kReplace);
@@ -481,7 +487,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(100, 100);
@@ -507,7 +513,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rotateClipped) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateClipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(100, 100);
@@ -545,7 +551,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rejectBegin) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rejectBegin) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(0, -20); // avoid identity case
@@ -560,7 +566,7 @@
     ASSERT_EQ(0u, dl->getOps().size()) << "Begin/Rect/End should all be rejected.";
 }
 
-TEST(RecordingCanvas, drawRenderNode_rejection) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_rejection) {
     auto child = TestUtils::createNode(50, 50, 150, 150,
             [](RenderProperties& props, Canvas& canvas) {
         SkPaint paint;
@@ -575,7 +581,7 @@
     ASSERT_TRUE(dl->isEmpty());
 }
 
-TEST(RecordingCanvas, drawRenderNode_projection) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_projection) {
     sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
             [](RenderProperties& props, Canvas& canvas) {
         SkPaint paint;
@@ -618,7 +624,7 @@
     }
 }
 
-TEST(RecordingCanvas, firstClipWillReplace) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, firstClipWillReplace) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         // since no explicit clip set on canvas, this should be the one observed on op:
@@ -635,7 +641,7 @@
     EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip);
 }
 
-TEST(RecordingCanvas, replaceClipIntersectWithRoot) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, replaceClipIntersectWithRoot) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(-10, -10, 110, 110, SkClipOp::kReplace);
@@ -648,7 +654,7 @@
     EXPECT_TRUE(dl->getOps()[0]->localClip->intersectWithRoot);
 }
 
-TEST(RecordingCanvas, insertReorderBarrier) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawRect(0, 0, 400, 400, SkPaint());
         canvas.insertReorderBarrier(true);
@@ -669,7 +675,7 @@
     EXPECT_TRUE(chunks[1].reorderChildren);
 }
 
-TEST(RecordingCanvas, insertReorderBarrier_clip) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier_clip) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // first chunk: no recorded clip
         canvas.insertReorderBarrier(true);
@@ -699,7 +705,7 @@
     EXPECT_EQ(Rect(200, 200), chunks[2].reorderClip->rect);
 }
 
-TEST(RecordingCanvas, refPaint) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refPaint) {
     SkPaint paint;
 
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
@@ -727,7 +733,7 @@
     EXPECT_NE(&paint, ops[2]->paint);
 }
 
-TEST(RecordingCanvas, refBitmap) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmap) {
     sk_sp<Bitmap> bitmap(TestUtils::createBitmap(100, 100));
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         canvas.drawBitmap(*bitmap, 0, 0, nullptr);
@@ -736,7 +742,7 @@
     EXPECT_EQ(1u, bitmaps.size());
 }
 
-TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
     sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         SkPaint paint;
@@ -755,7 +761,7 @@
     EXPECT_EQ(1u, bitmaps.size());
 }
 
-TEST(RecordingCanvas, refBitmapInShader_composeShader) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_composeShader) {
     sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         SkPaint paint;
@@ -785,7 +791,7 @@
     EXPECT_EQ(1u, bitmaps.size());
 }
 
-TEST(RecordingCanvas, drawText) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawText) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         Paint paint;
         paint.setAntiAlias(true);
@@ -807,7 +813,7 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(RecordingCanvas, drawTextInHighContrast) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.setHighContrastText(true);
         Paint paint;
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index f5ff058..2f1eae3 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -865,10 +865,8 @@
         void onDrawPaint(const SkPaint&) {
             switch (mDrawCounter++) {
             case 0:
-                // While this mirrors FrameBuilder::colorOp_unbounded, this value is different
-                // because there is no root (root is clipped in SkiaPipeline::renderFrame).
-                // SkiaPipeline.clipped and clip_replace verify the root clip.
-                EXPECT_TRUE(TestUtils::getClipBounds(this).isEmpty());
+                EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
+                        TestUtils::getClipBounds(this));
                 break;
             case 1:
                 EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 331a6ac..ab8e4e1 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -137,10 +137,11 @@
 RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
 
     VectorDrawable::Group* group = new VectorDrawable::Group();
-    VectorDrawableRoot* vectorDrawable = new VectorDrawableRoot(group);
+    sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
+
     auto rootNode = TestUtils::createNode(0, 0, 200, 400,
             [&](RenderProperties& props, Canvas& canvas) {
-        canvas.drawVectorDrawable(vectorDrawable);
+        canvas.drawVectorDrawable(vectorDrawable.get());
     });
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
@@ -164,7 +165,5 @@
     EXPECT_FALSE(info.layerUpdateQueue->entries().empty());
     EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode);
     EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage);
-
-    delete vectorDrawable;
     canvasContext->destroy(nullptr);
 }
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 95f9974..0ac09ac 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -28,7 +28,7 @@
  * Verify that we get the same culling bounds for text for (1) drawing glyphs
  * directly to a Canvas or (2) going through a SkPicture as an intermediate step.
  */
-TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
+OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // setup test variables
         SkPaint paint;
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 899758a..8f6fc8b 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -118,7 +118,7 @@
     }
 };
 
-RENDERTHREAD_TEST(SkiaDisplayList, prepareListAndChildren) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
     auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 494585a..0b8c2a9 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -36,7 +36,7 @@
 using namespace android::uirenderer::renderthread;
 using namespace android::uirenderer::skiapipeline;
 
-RENDERTHREAD_TEST(SkiaPipeline, renderFrame) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
     auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -55,7 +55,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckOpaque) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
     auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
         [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
             SkPaint greenPaint;
@@ -80,7 +80,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
     auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -101,7 +101,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderLayer) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
     auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -144,7 +144,7 @@
     blueNode->setLayerSurface(sk_sp<SkSurface>());
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
     ScopedProperty<bool> prop(Properties::debugOverdraw, true);
 
     auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
@@ -218,7 +218,7 @@
 };
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
     class DeferTestCanvas : public SkCanvas {
     public:
         DeferTestCanvas() : SkCanvas(800, 600) {}
@@ -284,7 +284,7 @@
     EXPECT_EQ(4, surface->canvas()->mDrawCounter);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, clipped) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) {
     static const int CANVAS_WIDTH = 200;
     static const int CANVAS_HEIGHT = 200;
     class ClippedTestCanvas : public SkCanvas {
@@ -315,7 +315,7 @@
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, clip_replace) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
     static const int CANVAS_WIDTH = 50;
     static const int CANVAS_HEIGHT = 50;
     class ClipReplaceTestCanvas : public SkCanvas {
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index e7171c8..95c6ed6 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -73,7 +73,7 @@
 
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropClipping) {
+TEST(RenderNodeDrawable, renderPropClipping) {
     testProperty([](RenderProperties& properties) {
         properties.setClipToBounds(true);
         properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
@@ -83,38 +83,24 @@
     });
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropRevealClip) {
+TEST(RenderNodeDrawable, renderPropRevealClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableRevealClip().set(true, 50, 50, 25);
     }, [](const SkCanvas& canvas) {
-        SkClipStack::Iter it(*canvas.getClipStack(), SkClipStack::Iter::kBottom_IterStart);
-        const SkClipStack::Element *top = it.next();
-        ASSERT_NE(nullptr, top);
-        SkPath clip;
-        top->asPath(&clip);
-        SkRect rect;
-        EXPECT_TRUE(clip.isOval(&rect));
-        EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), rect);
+        EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas));
     });
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropOutlineClip) {
+TEST(RenderNodeDrawable, renderPropOutlineClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableOutline().setShouldClip(true);
         properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
     }, [](const SkCanvas& canvas) {
-        SkClipStack::Iter it(*canvas.getClipStack(), SkClipStack::Iter::kBottom_IterStart);
-        const SkClipStack::Element *top = it.next();
-        ASSERT_NE(nullptr, top);
-        SkPath clip;
-        top->asPath(&clip);
-        SkRRect rrect;
-        EXPECT_TRUE(clip.isRRect(&rrect));
-        EXPECT_EQ(SkRRect::MakeRectXY(SkRect::MakeLTRB(10, 20, 30, 40), 5.0f, 5.0f), rrect);
+        EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas));
     });
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropTransform) {
+TEST(RenderNodeDrawable, renderPropTransform) {
     testProperty([](RenderProperties& properties) {
         properties.setLeftTopRightBottom(10, 10, 110, 110);
 
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 0d26df2..8312bda 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -26,7 +26,7 @@
 using namespace android;
 using namespace android::uirenderer;
 
-RENDERTHREAD_TEST(TextDropShadowCache, addRemove) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) {
     SkPaint paint;
     paint.setTextSize(20);
 
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index d2873e9..aac9727 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -47,7 +47,7 @@
     private double mCarrierPhaseUncertainty;
     private int mMultipathIndicator;
     private double mSnrInDb;
-    private double mAgcLevelDb;
+    private double mAutomaticGainControlLevelInDb;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -117,14 +117,12 @@
      * This GNSS measurement's tracking state has time-of-week known, possibly not decoded
      * over the air but has been determined from other sources. If TOW decoded is set then TOW Known
      * will also be set.
-     * @hide
      */
     public static final int STATE_TOW_KNOWN = (1<<14);
     /**
      * This Glonass measurement's tracking state has time-of-day known, possibly not decoded
      * over the air but has been determined from other sources. If TOD decoded is set then TOD Known
      * will also be set.
-     * @hide
      */
     public static final int STATE_GLO_TOD_KNOWN = (1<<15);
 
@@ -196,7 +194,7 @@
         mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty;
         mMultipathIndicator = measurement.mMultipathIndicator;
         mSnrInDb = measurement.mSnrInDb;
-        mAgcLevelDb = measurement.mAgcLevelDb;
+        mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
     }
 
     /**
@@ -662,8 +660,14 @@
     /**
      * Gets the carrier frequency of the tracked signal.
      *
-     * <p>For example it can be the GPS L1 = 1.57542e9 Hz, or L2, L5, varying GLO channels, etc. If
-     * the field is not set, it is the primary common use frequency, e.g. L1 for GPS.
+     * <p>For example it can be the GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz,
+     * L5 = 1176.45 MHz, varying GLO channels, etc. If the field is not set, it is the primary
+     * common use central frequency, e.g. L1 = 1575.45 MHz for GPS.
+     *
+     * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two raw
+     * measurement objects will be reported for this same satellite, in one of the measurement
+     * objects, all the values related to L1 will be filled, and in the other all of the values
+     * related to L5 will be filled.
      *
      * <p>The value is only available if {@link #hasCarrierFrequencyHz()} is {@code true}.
      */
@@ -884,48 +888,50 @@
     }
 
     /**
-     * Returns {@code true} if {@link #getAgcLevelDb()} is available, {@code false} otherwise.
-     * @hide
+     * Returns {@code true} if {@link #getAutomaticGainControlLevelInDb()} is available,
+     * {@code false} otherwise.
      */
-    public boolean hasAgcLevelDb() {
+    public boolean hasAutomaticGainControlLevelInDb() {
         return isFlagSet(HAS_AUTOMATIC_GAIN_CONTROL);
     }
 
     /**
      * Gets the Automatic Gain Control level in dB.
      *
-     * <p> AGC acts as a variable gain amplifier adjusting the power of the incoming signal to
-     * minimize the quantization losses. The AGC level may be used to indicate potential
-     * interference. When AGC is at a nominal level, this value must be set as 0.  Higher gain
-     * (and/or lower input power) shall be output as a positive number. Hence in cases of strong
-     * jamming, in the band of this signal, this value will go more negative.
+     * <p> AGC acts as a variable gain amplifier adjusting the power of the incoming signal. The AGC
+     * level may be used to indicate potential interference. When AGC is at a nominal level, this
+     * value must be set as 0. Higher gain (and/or lower input power) shall be output as a positive
+     * number. Hence in cases of strong jamming, in the band of this signal, this value will go more
+     * negative.
+     *
      * <p>Note: Different hardware designs (e.g. antenna, pre-amplification, or other RF HW
      * components) may also affect the typical output of of this value on any given hardware design
      * in an open sky test - the important aspect of this output is that changes in this value are
      * indicative of changes on input signal power in the frequency band for this measurement.
-     * <p>The value is only available if {@link #hasAgcLevelDb()} is {@code true}.
-     * @hide
+     * <p>The value is only available if {@link #hasAutomaticGainControlLevelInDb()} is {@code true}
      */
-    public double getAgcLevelDb() {
-        return mAgcLevelDb;
+    public double getAutomaticGainControlLevelInDb() {
+        return mAutomaticGainControlLevelInDb;
     }
 
     /**
      * Sets the Automatic Gain Control level in dB.
      * @hide
      */
-    public void setAgcLevelDb(double agcLevelDb) {
+    @TestApi
+    public void setAutomaticGainControlLevelInDb(double agcLevelDb) {
         setFlag(HAS_AUTOMATIC_GAIN_CONTROL);
-        mAgcLevelDb = agcLevelDb;
+        mAutomaticGainControlLevelInDb = agcLevelDb;
     }
 
     /**
      * Resets the Automatic Gain Control level.
      * @hide
      */
-    public void resetAgcLevel() {
+    @TestApi
+    public void resetAutomaticGainControlLevel() {
         resetFlag(HAS_AUTOMATIC_GAIN_CONTROL);
-        mAgcLevelDb = Double.NaN;
+        mAutomaticGainControlLevelInDb = Double.NaN;
     }
 
     public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@@ -952,7 +958,7 @@
             gnssMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
             gnssMeasurement.mMultipathIndicator = parcel.readInt();
             gnssMeasurement.mSnrInDb = parcel.readDouble();
-            gnssMeasurement.mAgcLevelDb = parcel.readDouble();
+            gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
 
             return gnssMeasurement;
         }
@@ -984,7 +990,7 @@
         parcel.writeDouble(mCarrierPhaseUncertainty);
         parcel.writeInt(mMultipathIndicator);
         parcel.writeDouble(mSnrInDb);
-        parcel.writeDouble(mAgcLevelDb);
+        parcel.writeDouble(mAutomaticGainControlLevelInDb);
     }
 
     @Override
@@ -1058,7 +1064,7 @@
         builder.append(String.format(
             format,
             "AgcLevelDb",
-            hasAgcLevelDb() ? mAgcLevelDb : null));
+            hasAutomaticGainControlLevelInDb() ? mAutomaticGainControlLevelInDb : null));
 
         return builder.toString();
     }
@@ -1082,7 +1088,7 @@
         resetCarrierPhaseUncertainty();
         setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
         resetSnrInDb();
-        resetAgcLevel();
+        resetAutomaticGainControlLevel();
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 6565042cc..e90a174 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -223,7 +223,6 @@
      * frequency is available for the satellite at the specified index).
      *
      * @param satIndex the index of the satellite in the list.
-     * @hide
      */
     public boolean hasCarrierFrequency(int satIndex) {
         return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) != 0;
@@ -232,11 +231,15 @@
     /**
      * Gets the carrier frequency of the signal tracked.
      *
-     * For example it can be the GPS L1 = 1.57542e9 Hz, or L2, L5, varying GLO channels, etc. If
-     * the field is not set, it is the primary common use frequency, e.g. L1 for GPS.
+     * <p>For example it can be the GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz,
+     * L5 = 1176.45 MHz, varying GLO channels, etc. If the field is not set, it is the primary
+     * common use central frequency, e.g. L1 = 1575.45 MHz for GPS.
+     *
+     * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two measurements
+     * will be reported for this same satellite, in one all the values related to L1 will be filled,
+     * and in the other all of the values related to L5 will be filled.
      *
      * <p>The value is only available if {@link #hasCarrierFrequency(int satIndex)} is {@code true}.
-     * @hide
      */
     public float getCarrierFrequencyHz(int satIndex) {
         return mCarrierFrequencies[satIndex];
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index f5f437e..b222a6d 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -798,7 +798,6 @@
 
     /**
      * True if this location has a vertical accuracy.
-     * @hide
      */
     public boolean hasVerticalAccuracy() {
         return (mFieldsMask & HAS_VERTICAL_ACCURACY_MASK) != 0;
@@ -818,7 +817,6 @@
      * errors do not always follow such a simple distribution.
      *
      * <p>If this location does not have a vertical accuracy, then 0.0 is returned.
-     * @hide
      */
     public float getVerticalAccuracyMeters() {
         return mVerticalAccuracyMeters;
@@ -830,7 +828,6 @@
      * <p>See {@link #getVerticalAccuracyMeters} for the definition of vertical accuracy.
      *
      * <p>Following this call {@link #hasVerticalAccuracy} will return true.
-     * @hide
      */
     public void setVerticalAccuracyMeters(float verticalAccuracyMeters) {
         mVerticalAccuracyMeters = verticalAccuracyMeters;
@@ -842,7 +839,6 @@
      *
      * <p>Following this call {@link #hasVerticalAccuracy} will return false, and
      * {@link #getVerticalAccuracyMeters} will return 0.0.
-     * @hide
      */
     public void removeVerticalAccuracy() {
         mVerticalAccuracyMeters = 0.0f;
@@ -851,7 +847,6 @@
 
     /**
      * True if this location has a speed accuracy.
-     * @hide
      */
     public boolean hasSpeedAccuracy() {
         return (mFieldsMask & HAS_SPEED_ACCURACY_MASK) != 0;
@@ -866,7 +861,6 @@
      * inside the circle.
      *
      * <p>If this location does not have a speed accuracy, then 0.0 is returned.
-     * @hide
      */
     public float getSpeedAccuracyMetersPerSecond() {
         return mSpeedAccuracyMetersPerSecond;
@@ -878,7 +872,6 @@
      * <p>See {@link #getSpeedAccuracyMetersPerSecond} for the definition of speed accuracy.
      *
      * <p>Following this call {@link #hasSpeedAccuracy} will return true.
-     * @hide
      */
     public void setSpeedAccuracyMetersPerSecond(float speedAccuracyMeterPerSecond) {
         mSpeedAccuracyMetersPerSecond = speedAccuracyMeterPerSecond;
@@ -890,7 +883,6 @@
      *
      * <p>Following this call {@link #hasSpeedAccuracy} will return false, and
      * {@link #getSpeedAccuracyMetersPerSecond} will return 0.0.
-     * @hide
      */
     public void removeSpeedAccuracy() {
         mSpeedAccuracyMetersPerSecond = 0.0f;
@@ -899,7 +891,6 @@
 
     /**
      * True if this location has a bearing accuracy.
-     * @hide
      */
     public boolean hasBearingAccuracy() {
         return (mFieldsMask & HAS_BEARING_ACCURACY_MASK) != 0;
@@ -914,7 +905,6 @@
      * inside the circle.
      *
      * <p>If this location does not have a bearing accuracy, then 0.0 is returned.
-     * @hide
      */
     public float getBearingAccuracyDegrees() {
         return mBearingAccuracyDegrees;
@@ -926,7 +916,6 @@
      * <p>See {@link #getBearingAccuracyDegrees} for the definition of bearing accuracy.
      *
      * <p>Following this call {@link #hasBearingAccuracy} will return true.
-     * @hide
      */
     public void setBearingAccuracyDegrees(float bearingAccuracyDegrees) {
         mBearingAccuracyDegrees = bearingAccuracyDegrees;
@@ -938,7 +927,6 @@
      *
      * <p>Following this call {@link #hasBearingAccuracy} will return false, and
      * {@link #getBearingAccuracyDegrees} will return 0.0.
-     * @hide
      */
     public void removeBearingAccuracy() {
         mBearingAccuracyDegrees = 0.0f;
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index b38a07f..dd9c6a7 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -283,10 +283,19 @@
 
     /**
      * @hide
-     * FIXME return a player proxy instead, make systemApi
-     * @return
+     * Return a proxy for the player associated with this playback configuration
+     * @return a proxy player
      */
-    public IPlayer getPlayerProxy() {
+    @SystemApi
+    public PlayerProxy getPlayerProxy() {
+        return mIPlayerShell == null ? null : new PlayerProxy(this);
+    }
+
+    /**
+     * @hide
+     * @return the IPlayer interface for the associated player
+     */
+    IPlayer getIPlayer() {
         return mIPlayerShell == null ? null : mIPlayerShell.getIPlayer();
     }
 
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 64576ec..e62dfaa 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -801,6 +801,28 @@
     }
 
     /**
+     * Sets the next output file descriptor to be used when the maximum filesize is reached
+     * on the prior output {@link #setOutputFile} or {@link #setNextOutputFile}). File descriptor
+     * must be seekable and in read-write mode. After setting the next output file, application
+     * should not use the file referenced by this file descriptor until {@link #stop}. Application
+     * must call this after receiving on the {@link android.media.MediaRecorder.OnInfoListener} a
+     * "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving
+     * a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used
+     * until switching to that output. Application will receive
+     * {@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED} when the next output file is used.
+     * Application will not be able to set a new output file if the previous one has not been used.
+     * Application is responsible for cleaning up unused files after {@link #stop} is called.
+     *
+     * @param fd an open file descriptor to be written into.
+     * @throws IllegalStateException if it is called before prepare().
+     * @throws IOException if setNextOutputFile fails otherwise.
+     */
+    public void setNextOutputFile(FileDescriptor fd) throws IllegalStateException, IOException
+    {
+        _setNextOutputFile(fd);
+    }
+
+    /**
      * Sets the path of the output file to be produced. Call this after
      * setOutputFormat() but before prepare().
      *
@@ -814,9 +836,38 @@
         mPath = path;
     }
 
+    /**
+     * Sets the next output file path to be used when the maximum filesize is reached
+     * on the prior output {@link #setOutputFile} or {@link #setNextOutputFile}). File should
+     * be seekable. After setting the next output file, application should not use the file
+     * referenced by this file descriptor until {@link #stop}. Application must call this
+     * after receiving on the {@link android.media.MediaRecorder.OnInfoListener} a "what" code of
+     * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving a "what" code of
+     * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used until switching to
+     * that output. Application will receive {@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED}
+     * when the next output file is used. Application will not be able to set a new output file if
+     * the previous one has not been used. Application is responsible for cleaning up unused files
+     * after {@link #stop} is called.
+     *
+     * @param  path The pathname to use.
+     * @throws IllegalStateException if it is called before prepare().
+     * @throws IOException if setNextOutputFile fails otherwise.
+     */
+    public void setNextOutputFile(String path) throws IllegalStateException, IOException
+    {
+        if (path != null) {
+            RandomAccessFile file = new RandomAccessFile(path, "rws");
+            try {
+                _setNextOutputFile(file.getFD());
+            } finally {
+                file.close();
+            }
+        }
+    }
+
     // native implementation
-    private native void _setOutputFile(FileDescriptor fd, long offset, long length)
-        throws IllegalStateException, IOException;
+    private native void _setOutputFile(FileDescriptor fd) throws IllegalStateException, IOException;
+    private native void _setNextOutputFile(FileDescriptor fd) throws IllegalStateException, IOException;
     private native void _prepare() throws IllegalStateException, IOException;
 
     /**
@@ -833,12 +884,12 @@
         if (mPath != null) {
             RandomAccessFile file = new RandomAccessFile(mPath, "rws");
             try {
-                _setOutputFile(file.getFD(), 0, 0);
+                _setOutputFile(file.getFD());
             } finally {
                 file.close();
             }
         } else if (mFd != null) {
-            _setOutputFile(mFd, 0, 0);
+            _setOutputFile(mFd);
         } else {
             throw new IOException("No valid output file");
         }
@@ -980,9 +1031,26 @@
      */
     public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800;
     /** A maximum filesize had been setup and has now been reached.
+     * Note: This event will not be sent if application already set
+     * next output file through {@link #setNextOutputFile}.
      * @see android.media.MediaRecorder.OnInfoListener
      */
     public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801;
+    /** A maximum filesize had been setup and current recorded file size
+     * has reached 90% of the limit. This is sent once per file upon
+     * reaching/passing the 90% limit. To continue the recording, applicaiton
+     * should use {@link #setNextOutputFile} to set the next output file.
+     * Otherwise, recording will stop when reaching maximum file size.
+     * @see android.media.MediaRecorder.OnInfoListener
+     */
+    public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802;
+    /** A maximum filesize had been reached and MediaRecorder has switched
+     * output to a new file set by application {@link #setNextOutputFile}.
+     * For best practice, application should use this event to keep track
+     * of whether the file previously set has been used or not.
+     * @see android.media.MediaRecorder.OnInfoListener
+     */
+    public static final int MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803;
 
     /** informational events for individual tracks, for testing purpose.
      * The track informational event usually contains two parts in the ext1
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 9819395..bd0a1b4 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -78,6 +78,7 @@
         }
         mAttributes = attr;
         mImplType = implType;
+        mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
     };
 
     /**
@@ -138,7 +139,8 @@
     void baseStart() {
         if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
         try {
-            getService().playerEvent(mPlayerIId, AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
+            mState = AudioPlaybackConfiguration.PLAYER_STATE_STARTED;
+            getService().playerEvent(mPlayerIId, mState);
         } catch (RemoteException e) {
             Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e);
         }
@@ -152,7 +154,8 @@
     void basePause() {
         if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
         try {
-            getService().playerEvent(mPlayerIId, AudioPlaybackConfiguration.PLAYER_STATE_PAUSED);
+            mState = AudioPlaybackConfiguration.PLAYER_STATE_PAUSED;
+            getService().playerEvent(mPlayerIId, mState);
         } catch (RemoteException e) {
             Log.e(TAG, "Error talking to audio service, PAUSED state will not be tracked", e);
         }
@@ -161,7 +164,8 @@
     void baseStop() {
         if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
         try {
-            getService().playerEvent(mPlayerIId, AudioPlaybackConfiguration.PLAYER_STATE_STOPPED);
+            mState = AudioPlaybackConfiguration.PLAYER_STATE_STOPPED;
+            getService().playerEvent(mPlayerIId, mState);
         } catch (RemoteException e) {
             Log.e(TAG, "Error talking to audio service, STOPPED state will not be tracked", e);
         }
@@ -193,7 +197,7 @@
      * Releases AppOps related resources.
      */
     void baseRelease() {
-        if (DEBUG) { Log.v(TAG, "baseRelease() piid=" + mPlayerIId); }
+        if (DEBUG) { Log.v(TAG, "baseRelease() piid=" + mPlayerIId + " state=" + mState); }
         try {
             if (mState != AudioPlaybackConfiguration.PLAYER_STATE_RELEASED) {
                 getService().releasePlayer(mPlayerIId);
diff --git a/media/java/android/media/PlayerProxy.java b/media/java/android/media/PlayerProxy.java
new file mode 100644
index 0000000..171be27
--- /dev/null
+++ b/media/java/android/media/PlayerProxy.java
@@ -0,0 +1,109 @@
+/*
+ * 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.IllegalArgumentException;
+import java.util.Objects;
+
+/**
+ * Class to remotely control a player.
+ * @hide
+ */
+@SystemApi
+public class PlayerProxy {
+
+    private final static String TAG = "PlayerProxy";
+    private final static boolean DEBUG = false;
+
+    private final AudioPlaybackConfiguration mConf; // never null
+
+    /**
+     * @hide
+     * Constructor. Proxy for this player associated with this AudioPlaybackConfiguration
+     * @param conf the configuration being proxied.
+     */
+    PlayerProxy(@NonNull AudioPlaybackConfiguration apc) {
+        if (apc == null) {
+            throw new IllegalArgumentException("Illegal null AudioPlaybackConfiguration");
+        }
+        mConf = apc;
+    };
+
+    //=====================================================================
+    // Methods matching the IPlayer interface
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void start() throws IllegalStateException {
+        try {
+            mConf.getIPlayer().start();
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for start operation, player already released?", e);
+        }
+    }
+
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void pause() throws IllegalStateException {
+        try {
+            mConf.getIPlayer().pause();
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for pause operation, player already released?", e);
+        }
+    }
+
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void stop() throws IllegalStateException {
+        try {
+            mConf.getIPlayer().stop();
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for stop operation, player already released?", e);
+        }
+    }
+
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void setVolume(float vol) throws IllegalStateException {
+        try {
+            mConf.getIPlayer().setVolume(vol);
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for setVolume operation, player already released?", e);
+        }
+    }
+
+}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 16847c1..eaec493 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -387,7 +387,6 @@
      * @see BrowserRoot#EXTRA_RECENT
      * @see BrowserRoot#EXTRA_OFFLINE
      * @see BrowserRoot#EXTRA_SUGGESTED
-     * @see BrowserRoot#EXTRA_SUGGESTION_KEYWORDS
      */
     public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
             int clientUid, @Nullable Bundle rootHints);
@@ -550,7 +549,6 @@
      * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
      * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
      * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
-     * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTION_KEYWORDS
      */
     public final Bundle getBrowserRootHints() {
         if (mCurConnection == null) {
@@ -818,7 +816,6 @@
          *
          * @see #EXTRA_OFFLINE
          * @see #EXTRA_SUGGESTED
-         * @see #EXTRA_SUGGESTION_KEYWORDS
          */
         public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
 
@@ -836,7 +833,6 @@
          *
          * @see #EXTRA_RECENT
          * @see #EXTRA_SUGGESTED
-         * @see #EXTRA_SUGGESTION_KEYWORDS
          */
         public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
 
@@ -855,31 +851,9 @@
          *
          * @see #EXTRA_RECENT
          * @see #EXTRA_OFFLINE
-         * @see #EXTRA_SUGGESTION_KEYWORDS
          */
         public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
 
-        /**
-         * The lookup key for a string that indicates specific keywords which will be considered
-         * when the browser service suggests media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint together with {@link #EXTRA_SUGGESTED} for retrieving suggested
-         * media items related with the keywords. The list of media items passed in
-         * {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
-         * is considered ordered by relevance, first being the top suggestion.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_RECENT
-         * @see #EXTRA_OFFLINE
-         * @see #EXTRA_SUGGESTED
-         */
-        public static final String EXTRA_SUGGESTION_KEYWORDS
-                = "android.service.media.extra.SUGGESTION_KEYWORDS";
-
         final private String mRootId;
         final private Bundle mExtras;
 
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 6c79ab7..7c509d2 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -290,7 +290,7 @@
 }
 
 static void
-android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
+android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor)
 {
     ALOGV("setOutputFile");
     if (fileDescriptor == NULL) {
@@ -303,7 +303,25 @@
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
-    status_t opStatus = mr->setOutputFile(fd, offset, length);
+    status_t opStatus = mr->setOutputFile(fd);
+    process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
+}
+
+static void
+android_media_MediaRecorder_setNextOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor)
+{
+    ALOGV("setNextOutputFile");
+    if (fileDescriptor == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+    if (mr == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+    status_t opStatus = mr->setNextOutputFile(fd);
     process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
 }
 
@@ -617,7 +635,8 @@
     {"setVideoEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setVideoEncoder},
     {"setAudioEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setAudioEncoder},
     {"setParameter",         "(Ljava/lang/String;)V",           (void *)android_media_MediaRecorder_setParameter},
-    {"_setOutputFile",       "(Ljava/io/FileDescriptor;JJ)V",   (void *)android_media_MediaRecorder_setOutputFileFD},
+    {"_setOutputFile",       "(Ljava/io/FileDescriptor;)V",     (void *)android_media_MediaRecorder_setOutputFileFD},
+    {"_setNextOutputFile",   "(Ljava/io/FileDescriptor;)V",     (void *)android_media_MediaRecorder_setNextOutputFileFD},
     {"setVideoSize",         "(II)V",                           (void *)android_media_MediaRecorder_setVideoSize},
     {"setVideoFrameRate",    "(I)V",                            (void *)android_media_MediaRecorder_setVideoFrameRate},
     {"setMaxDuration",       "(I)V",                            (void *)android_media_MediaRecorder_setMaxDuration},
diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk
index 2abd7f6..eb451f7 100644
--- a/media/mca/tests/Android.mk
+++ b/media/mca/tests/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 308c665..0d9f42b 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -10,7 +10,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target-minus-junit4 \
     android-support-test \
-    android-ex-camera2
+    android-ex-camera2 \
+    legacy-android-test
 
 LOCAL_PACKAGE_NAME := mediaframeworktest
 
diff --git a/native/android/Android.mk b/native/android/Android.mk
index da4e4ba..355f52e 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -9,6 +9,7 @@
     asset_manager.cpp \
     choreographer.cpp \
     configuration.cpp \
+    hardware_buffer.cpp \
     input.cpp \
     looper.cpp \
     native_activity.cpp \
diff --git a/native/android/hardware_buffer.cpp b/native/android/hardware_buffer.cpp
new file mode 100644
index 0000000..6a10cb5
--- /dev/null
+++ b/native/android/hardware_buffer.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHardwareBuffer"
+
+#include <android/hardware_buffer_jni.h>
+
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <memory>
+
+#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 <gui/ISurfaceComposer.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Flattenable.h>
+#include <utils/Log.h>
+
+static constexpr int kDataBufferSize = 64 * sizeof(int);  // 64 ints
+
+using namespace android;
+
+static inline const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
+        const AHardwareBuffer* buffer) {
+    return reinterpret_cast<const GraphicBuffer*>(buffer);
+}
+
+static inline GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(
+        AHardwareBuffer* buffer) {
+    return reinterpret_cast<GraphicBuffer*>(buffer);
+}
+
+static inline AHardwareBuffer* GraphicBuffer_to_AHardwareBuffer(
+        GraphicBuffer* buffer) {
+    return reinterpret_cast<AHardwareBuffer*>(buffer);
+}
+
+// ----------------------------------------------------------------------------
+// Public functions
+// ----------------------------------------------------------------------------
+
+int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
+        AHardwareBuffer** outBuffer) {
+    if (!outBuffer || !desc) return BAD_VALUE;
+
+    // The holder is used to destroy the buffer if an error occurs.
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == nullptr) {
+        ALOGE("Unable to connect to ServiceManager");
+        return PERMISSION_DENIED;
+    }
+
+    // Get the SurfaceFlingerService.
+    sp<ISurfaceComposer> composer = interface_cast<ISurfaceComposer>(
+            sm->getService(String16("SurfaceFlinger")));
+    if (composer == nullptr) {
+        ALOGE("Unable to connect to surface composer");
+        return PERMISSION_DENIED;
+    }
+    // Get an IGraphicBufferAlloc to create the buffer.
+    sp<IGraphicBufferAlloc> allocator = composer->createGraphicBufferAlloc();
+    if (allocator == nullptr) {
+        ALOGE("Unable to obtain a buffer allocator");
+        return PERMISSION_DENIED;
+    }
+
+    int format = android_hardware_HardwareBuffer_convertToPixelFormat(
+            desc->format);
+    if (format == 0) {
+        ALOGE("Invalid pixel format");
+        return BAD_VALUE;
+    }
+
+    status_t err;
+    uint32_t usage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+            desc->usage0, desc->usage1);
+    sp<GraphicBuffer> gbuffer = allocator->createGraphicBuffer(desc->width,
+            desc->height, format, desc->layers, usage, &err);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    *outBuffer = GraphicBuffer_to_AHardwareBuffer(gbuffer.get());
+    // Ensure the buffer doesn't get destroyed with the sp<> goes away.
+    AHardwareBuffer_acquire(*outBuffer);
+    return NO_ERROR;
+}
+
+void AHardwareBuffer_acquire(AHardwareBuffer* buffer) {
+    AHardwareBuffer_to_GraphicBuffer(buffer)->incStrong(
+            (void*)AHardwareBuffer_acquire);
+}
+
+void AHardwareBuffer_release(AHardwareBuffer* buffer) {
+    AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong(
+            (void*)AHardwareBuffer_acquire);
+}
+
+void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
+        AHardwareBuffer_Desc* outDesc) {
+    if (!buffer || !outDesc) return;
+
+    const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+    outDesc->width = gbuffer->getWidth();
+    outDesc->height = gbuffer->getHeight();
+    outDesc->layers = gbuffer->getLayerCount();
+    outDesc->usage0 =
+            android_hardware_HardwareBuffer_convertFromGrallocUsageBits(
+                    gbuffer->getUsage());
+    outDesc->usage1 = 0;
+    outDesc->format = android_hardware_HardwareBuffer_convertFromPixelFormat(
+            static_cast<uint32_t>(gbuffer->getPixelFormat()));
+}
+
+int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage0,
+        int32_t fence, const ARect* rect, void** outVirtualAddress) {
+    if (!buffer) return BAD_VALUE;
+
+    if (usage0 & ~(AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN |
+            AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN)) {
+        ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+                " AHARDWAREBUFFER_USAGE0_CPU_* flags are allowed");
+        return BAD_VALUE;
+    }
+
+    uint32_t usage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+            usage0, 0);
+    GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+    if (!rect) {
+        return gBuffer->lockAsync(usage, outVirtualAddress, fence);
+    } else {
+        Rect bounds(rect->left, rect->top, rect->right, rect->bottom);
+        return gBuffer->lockAsync(usage, bounds, outVirtualAddress, fence);
+    }
+}
+
+int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) {
+    if (!buffer) return BAD_VALUE;
+
+    GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+    return gBuffer->unlockAsync(fence);
+}
+
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
+        int socketFd) {
+    if (!buffer) return BAD_VALUE;
+    const GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+    size_t flattenedSize = gBuffer->getFlattenedSize();
+    size_t fdCount = gBuffer->getFdCount();
+
+    std::unique_ptr<uint8_t[]> data(new uint8_t[flattenedSize]);
+    std::unique_ptr<int[]> fds(new int[fdCount]);
+
+    // Make copies of needed items since flatten modifies them, and we don't
+    // want to send anything if there's an error during flatten.
+    size_t flattenedSizeCopy = flattenedSize;
+    size_t fdCountCopy = fdCount;
+    void* dataStart = data.get();
+    int* fdsStart = fds.get();
+    status_t err = gBuffer->flatten(dataStart, flattenedSizeCopy, fdsStart,
+                fdCountCopy);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    struct iovec iov[1];
+    iov[0].iov_base = data.get();
+    iov[0].iov_len = flattenedSize;
+
+    char buf[CMSG_SPACE(kDataBufferSize)];
+    struct msghdr msg = {
+        .msg_control = buf,
+        .msg_controllen = sizeof(buf),
+        .msg_iov = &iov[0],
+        .msg_iovlen = 1,
+    };
+
+    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount);
+    int* fdData = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+    memcpy(fdData, fds.get(), sizeof(int) * fdCount);
+    msg.msg_controllen = cmsg->cmsg_len;
+
+    int result = sendmsg(socketFd, &msg, 0);
+    if (result <= 0) {
+        ALOGE("Error writing AHardwareBuffer to socket: error %#x (%s)",
+                result, strerror(errno));
+        return result;
+    }
+    return NO_ERROR;
+}
+
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
+        AHardwareBuffer** outBuffer) {
+    if (!outBuffer) return BAD_VALUE;
+
+    char dataBuf[CMSG_SPACE(kDataBufferSize)];
+    char fdBuf[CMSG_SPACE(kDataBufferSize)];
+    struct iovec iov[1];
+    iov[0].iov_base = dataBuf;
+    iov[0].iov_len = sizeof(dataBuf);
+
+    struct msghdr msg = {
+        .msg_control = fdBuf,
+        .msg_controllen = sizeof(fdBuf),
+        .msg_iov = &iov[0],
+        .msg_iovlen = 1,
+    };
+
+    int result = recvmsg(socketFd, &msg, 0);
+    if (result <= 0) {
+        ALOGE("Error reading AHardwareBuffer from socket: error %#x (%s)",
+                result, strerror(errno));
+        return result;
+    }
+
+    if (msg.msg_iovlen != 1) {
+        ALOGE("Error reading AHardwareBuffer from socket: bad data length");
+        return INVALID_OPERATION;
+    }
+
+    if (msg.msg_controllen % sizeof(int) != 0) {
+        ALOGE("Error reading AHardwareBuffer from socket: bad fd length");
+        return INVALID_OPERATION;
+    }
+
+    size_t dataLen = msg.msg_iov[0].iov_len;
+    const void* data = static_cast<const void*>(msg.msg_iov[0].iov_base);
+    if (!data) {
+        ALOGE("Error reading AHardwareBuffer from socket: no buffer data");
+        return INVALID_OPERATION;
+    }
+
+    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
+    if (!cmsg) {
+        ALOGE("Error reading AHardwareBuffer from socket: no fd header");
+        return INVALID_OPERATION;
+    }
+
+    size_t fdCount = msg.msg_controllen >> 2;
+    const int* fdData = reinterpret_cast<const int*>(CMSG_DATA(cmsg));
+    if (!fdData) {
+        ALOGE("Error reading AHardwareBuffer from socket: no fd data");
+        return INVALID_OPERATION;
+    }
+
+    GraphicBuffer* gBuffer = new GraphicBuffer();
+    status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    *outBuffer = GraphicBuffer_to_AHardwareBuffer(gBuffer);
+    // Ensure the buffer has a positive ref-count.
+    AHardwareBuffer_acquire(*outBuffer);
+
+    return NO_ERROR;
+}
+
+const struct native_handle* AHardwareBuffer_getNativeHandle(
+        const AHardwareBuffer* buffer) {
+    if (!buffer) return nullptr;
+    const GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+    return gbuffer->handle;
+}
+
+// ----------------------------------------------------------------------------
+// JNI functions
+// ----------------------------------------------------------------------------
+
+AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env,
+        jobject hardwareBufferObj) {
+    return android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
+            hardwareBufferObj);
+}
+
+jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env,
+        AHardwareBuffer* hardwareBuffer) {
+    return android_hardware_HardwareBuffer_createFromAHardwareBuffer(env,
+            hardwareBuffer);
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 5758a3c..f9e8fda 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -139,6 +139,17 @@
     ANativeActivity_setWindowFlags;
     ANativeActivity_setWindowFormat;
     ANativeActivity_showSoftInput;
+    AHardwareBuffer_acquire; # introduced=26
+    AHardwareBuffer_allocate; # introduced=26
+    AHardwareBuffer_describe; # introduced=26
+    AHardwareBuffer_fromHardwareBuffer; # introduced=26
+    AHardwareBuffer_getNativeHandle; # introduced=26
+    AHardwareBuffer_lock; # introduced=26
+    AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26
+    AHardwareBuffer_release; # introduced=26
+    AHardwareBuffer_sendHandleToUnixSocket; # introduced=26
+    AHardwareBuffer_toHardwareBuffer; # introduced=26
+    AHardwareBuffer_unlock; # introduced=26
     ANativeWindow_acquire;
     ANativeWindow_fromSurface;
     ANativeWindow_fromSurfaceTexture; # introduced-arm=13 introduced-mips=13 introduced-x86=13
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
index 330e2d4..cd7a45b 100644
--- a/nfc-extras/Android.mk
+++ b/nfc-extras/Android.mk
@@ -6,6 +6,8 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+
 LOCAL_MODULE:= com.android.nfc_extras
 
 include $(BUILD_JAVA_LIBRARY)
diff --git a/packages/BackupRestoreConfirmation/res/values-it/strings.xml b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
index b84edbc..1cbb770 100644
--- a/packages/BackupRestoreConfirmation/res/values-it/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
@@ -30,7 +30,7 @@
     <string name="backup_enc_password_text" msgid="4981585714795233099">"Inserisci una password da utilizzare per la crittografia dei dati di backup completi. Se non ne inserisci una, verrà utilizzata la tua password di backup corrente:"</string>
     <string name="backup_enc_password_optional" msgid="1350137345907579306">"Se desideri crittografare tutti i dati di backup, inserisci una password qui di seguito:"</string>
     <string name="backup_enc_password_required" msgid="7889652203371654149">"Il dispositivo è criptato, quindi devi criptare il backup. Inserisci una password di seguito:"</string>
-    <string name="restore_enc_password_text" msgid="6140898525580710823">"Se i dati di ripristino sono crittografati, inserisci la password qui di seguito:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"Se i dati di ripristino sono criptati, inserisci la password qui di seguito:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Avvio del backup..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Backup terminato"</string>
     <string name="toast_restore_started" msgid="7881679218971277385">"Avvio del ripristino..."</string>
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.mk b/packages/CarrierDefaultApp/tests/unit/Android.mk
index 092df50..63bd0b1 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.mk
+++ b/packages/CarrierDefaultApp/tests/unit/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4 legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 91c943d..8cdb906 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -290,6 +290,7 @@
         monitor.reportFailedStrongAuthUnlockAttempt(userId);
         mLockPatternUtils.reportFailedPasswordAttempt(userId);
         if (timeoutMs > 0) {
+            mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
             showTimeoutDialog(userId, timeoutMs);
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index e1657c7..f8f4f2a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -29,6 +29,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.GridLayout;
 import android.widget.TextClock;
 import android.widget.TextView;
@@ -48,6 +49,7 @@
     private TextClock mDateView;
     private TextClock mClockView;
     private TextView mOwnerInfo;
+    private ViewGroup mClockContainer;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -105,6 +107,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mClockContainer = (ViewGroup) findViewById(R.id.keyguard_clock_container);
         mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
         mDateView = (TextClock) findViewById(R.id.date_view);
         mClockView = (TextClock) findViewById(R.id.clock_view);
@@ -167,6 +170,11 @@
         }
     }
 
+    public int getClockBottom() {
+        return mClockView.getBottom() +
+                ((MarginLayoutParams) mClockView.getLayoutParams()).bottomMargin;
+    }
+
     public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
         if (info == null) {
             return "";
@@ -260,4 +268,15 @@
             cacheKey = key;
         }
     }
+
+    public void setDark(boolean dark) {
+        final int N = mClockContainer.getChildCount();
+        for (int i = 0; i < N; i++) {
+            View child = mClockContainer.getChildAt(i);
+            if (child == mClockView) {
+                continue;
+            }
+            child.setAlpha(dark ? 0 : 1);
+        }
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0a7bdbf..80d4a26 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,7 +26,6 @@
 import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
 import static android.os.BatteryManager.EXTRA_PLUGGED;
 import static android.os.BatteryManager.EXTRA_STATUS;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 
 import android.app.ActivityManager;
 import android.app.AlarmManager;
@@ -106,12 +105,6 @@
     private static final String ACTION_FACE_UNLOCK_STOPPED
             = "com.android.facelock.FACE_UNLOCK_STOPPED";
 
-    private static final String ACTION_STRONG_AUTH_TIMEOUT =
-            "com.android.systemui.ACTION_STRONG_AUTH_TIMEOUT";
-    private static final String USER_ID = "com.android.systemui.USER_ID";
-
-    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
-
     // Callback messages
     private static final int MSG_TIME_UPDATE = 301;
     private static final int MSG_BATTERY_UPDATE = 302;
@@ -203,7 +196,6 @@
     private boolean mDeviceInteractive;
     private boolean mScreenOn;
     private SubscriptionManager mSubscriptionManager;
-    private AlarmManager mAlarmManager;
     private List<SubscriptionInfo> mSubscriptionInfo;
     private TrustManager mTrustManager;
     private UserManager mUserManager;
@@ -588,26 +580,12 @@
     }
 
     public void reportSuccessfulStrongAuthUnlockAttempt() {
-        scheduleStrongAuthTimeout();
         if (mFpm != null) {
             byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
             mFpm.resetTimeout(token);
         }
     }
 
-    private void scheduleStrongAuthTimeout() {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null,
-                sCurrentUser);
-        Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT);
-        intent.putExtra(USER_ID, sCurrentUser);
-        PendingIntent sender = PendingIntent.getBroadcast(mContext,
-                sCurrentUser, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, sender);
-        notifyStrongAuthStateChanged(sCurrentUser);
-    }
-
     private void notifyStrongAuthStateChanged(int userId) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -723,17 +701,6 @@
         }
     };
 
-    private final BroadcastReceiver mStrongAuthTimeoutReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) {
-                int userId = intent.getIntExtra(USER_ID, -1);
-                mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, userId);
-                notifyStrongAuthStateChanged(userId);
-            }
-        }
-    };
-
     private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
             = new FingerprintManager.LockoutResetCallback() {
         @Override
@@ -1034,7 +1001,6 @@
     private KeyguardUpdateMonitor(Context context) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
-        mAlarmManager = context.getSystemService(AlarmManager.class);
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
         mStrongAuthTracker = new StrongAuthTracker(context);
 
@@ -1094,10 +1060,6 @@
             e.rethrowAsRuntimeException();
         }
 
-        IntentFilter strongAuthTimeoutFilter = new IntentFilter();
-        strongAuthTimeoutFilter.addAction(ACTION_STRONG_AUTH_TIMEOUT);
-        context.registerReceiver(mStrongAuthTimeoutReceiver, strongAuthTimeoutFilter,
-                PERMISSION_SELF, null /* handler */);
         mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
         mTrustManager.registerTrustListener(this);
         mLockPatternUtils = new LockPatternUtils(context);
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index c9e7195..a9e9b2e 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -6,7 +6,6 @@
 LOCAL_PACKAGE_NAME := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
 LOCAL_PRIVILEGED_MODULE := true
-LOCAL_JNI_SHARED_LIBRARIES := libappfuse_jni
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
 # Only enable asserts on userdebug/eng builds
diff --git a/packages/MtpDocumentsProvider/jni/Android.mk b/packages/MtpDocumentsProvider/jni/Android.mk
deleted file mode 100644
index d545b14..0000000
--- a/packages/MtpDocumentsProvider/jni/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    com_android_mtp_AppFuse.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
-    libnativehelper \
-    liblog
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_MODULE := libappfuse_jni
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
deleted file mode 100644
index e948cf7..0000000
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ /dev/null
@@ -1,571 +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 specic language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AppFuseJNI"
-#include "utils/Log.h"
-
-#include <assert.h>
-#include <dirent.h>
-#include <inttypes.h>
-
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include <map>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "nativehelper/ScopedPrimitiveArray.h"
-#include "nativehelper/ScopedLocalRef.h"
-
-namespace {
-
-// The numbers came from sdcard.c.
-// Maximum number of bytes to write/read in one request/one reply.
-constexpr size_t MAX_WRITE = 256 * 1024;
-constexpr size_t MAX_READ = 128 * 1024;
-
-constexpr size_t NUM_MAX_HANDLES = 1024;
-
-// Largest possible request.
-// The request size is bounded by the maximum size of a FUSE_WRITE request
-// because it has the largest possible data payload.
-constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
-        sizeof(struct fuse_write_in) + (MAX_WRITE > MAX_READ ? MAX_WRITE : MAX_READ);
-
-static jclass app_fuse_class;
-static jmethodID app_fuse_get_file_size;
-static jmethodID app_fuse_read_object_bytes;
-static jmethodID app_fuse_write_object_bytes;
-static jmethodID app_fuse_flush_file_handle;
-static jmethodID app_fuse_close_file_handle;
-static jfieldID app_fuse_buffer;
-
-// NOTE:
-// FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
-// not access input buffer after writing data to output buffer.
-struct FuseRequest {
-    char buffer[MAX_REQUEST_SIZE];
-    FuseRequest() {}
-    const struct fuse_in_header& header() const {
-        return *(const struct fuse_in_header*) buffer;
-    }
-    void* data() {
-        return (buffer + sizeof(struct fuse_in_header));
-    }
-    size_t data_length() const {
-        return header().len - sizeof(struct fuse_in_header);
-    }
-};
-
-template<typename T>
-class FuseResponse {
-   size_t size_;
-   T* const buffer_;
-public:
-   explicit FuseResponse(void* buffer) : size_(0), buffer_(static_cast<T*>(buffer)) {}
-
-   void prepare_buffer(size_t size = sizeof(T)) {
-       memset(buffer_, 0, size);
-       size_ = size;
-   }
-
-   void set_size(size_t size) {
-       size_ = size;
-   }
-
-   size_t size() const { return size_; }
-   T* data() const { return buffer_; }
-};
-
-class ScopedFd {
-    int mFd;
-
-public:
-    explicit ScopedFd(int fd) : mFd(fd) {}
-    ~ScopedFd() {
-        close(mFd);
-    }
-    operator int() {
-        return mFd;
-    }
-};
-
-/**
- * Fuse implementation consists of handlers parsing FUSE commands.
- */
-class AppFuse {
-    JNIEnv* env_;
-    jobject self_;
-
-    // Map between file handle and inode.
-    std::map<uint32_t, uint64_t> handles_;
-    uint32_t handle_counter_;
-
-public:
-    AppFuse(JNIEnv* env, jobject self) :
-        env_(env), self_(self), handle_counter_(0) {}
-
-    void handle_fuse_request(int fd, FuseRequest* req) {
-        ALOGV("Request op=%d", req->header().opcode);
-        switch (req->header().opcode) {
-            // TODO: Handle more operations that are enough to provide seekable
-            // FD.
-            case FUSE_LOOKUP:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
-                return;
-            case FUSE_FORGET:
-                // Return without replying.
-                return;
-            case FUSE_INIT:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_init);
-                return;
-            case FUSE_GETATTR:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
-                return;
-            case FUSE_OPEN:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_open);
-                return;
-            case FUSE_READ:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_read);
-                return;
-            case FUSE_WRITE:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_write);
-                return;
-            case FUSE_RELEASE:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_release);
-                return;
-            case FUSE_FLUSH:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
-                return;
-            default: {
-                ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
-                      req->header().opcode,
-                      req->header().unique,
-                      req->header().nodeid);
-                fuse_reply(fd, req->header().unique, -ENOSYS, NULL, 0);
-                return;
-            }
-        }
-    }
-
-private:
-    int handle_fuse_lookup(const fuse_in_header& header,
-                           const char* name,
-                           FuseResponse<fuse_entry_out>* out) {
-        if (header.nodeid != 1) {
-            return -ENOENT;
-        }
-
-        const int n = atoi(name);
-        if (n == 0) {
-            return -ENOENT;
-        }
-
-        int64_t size = get_file_size(n);
-        if (size < 0) {
-            return -ENOENT;
-        }
-
-        out->prepare_buffer();
-        out->data()->nodeid = n;
-        out->data()->attr_valid = 10;
-        out->data()->entry_valid = 10;
-        out->data()->attr.ino = n;
-        out->data()->attr.mode = S_IFREG | 0777;
-        out->data()->attr.size = size;
-        return 0;
-    }
-
-    int handle_fuse_init(const fuse_in_header&,
-                         const fuse_init_in* in,
-                         FuseResponse<fuse_init_out>* out) {
-        // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
-        // defined (fuse version 7.6). The structure is the same from 7.6 through
-        // 7.22. Beginning with 7.23, the structure increased in size and added
-        // new parameters.
-        if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
-            ALOGE("Fuse kernel version mismatch: Kernel version %d.%d, "
-                  "Expected at least %d.6",
-                  in->major, in->minor, FUSE_KERNEL_VERSION);
-            return -1;
-        }
-
-        // Before writing |out|, we need to copy data from |in|.
-        const uint32_t minor = in->minor;
-        const uint32_t max_readahead = in->max_readahead;
-
-        // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
-        size_t response_size = sizeof(fuse_init_out);
-#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
-        // FUSE_KERNEL_VERSION >= 23.
-
-        // If the kernel only works on minor revs older than or equal to 22,
-        // then use the older structure size since this code only uses the 7.22
-        // version of the structure.
-        if (minor <= 22) {
-            response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
-        }
-#endif
-        out->prepare_buffer(response_size);
-        out->data()->major = FUSE_KERNEL_VERSION;
-        out->data()->minor = std::min(minor, 15u);
-        out->data()->max_readahead = max_readahead;
-        out->data()->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-        out->data()->max_background = 32;
-        out->data()->congestion_threshold = 32;
-        out->data()->max_write = MAX_WRITE;
-
-        return 0;
-    }
-
-    int handle_fuse_getattr(const fuse_in_header& header,
-                            const fuse_getattr_in* /* in */,
-                            FuseResponse<fuse_attr_out>* out) {
-        out->prepare_buffer();
-        out->data()->attr_valid = 10;
-        out->data()->attr.ino = header.nodeid;
-        if (header.nodeid == 1) {
-            out->data()->attr.mode = S_IFDIR | 0777;
-            out->data()->attr.size = 0;
-        } else {
-            int64_t size = get_file_size(header.nodeid);
-            if (size < 0) {
-                return -ENOENT;
-            }
-            out->data()->attr.mode = S_IFREG | 0777;
-            out->data()->attr.size = size;
-        }
-
-        return 0;
-    }
-
-    int handle_fuse_open(const fuse_in_header& header,
-                         const fuse_open_in* /* in */,
-                         FuseResponse<fuse_open_out>* out) {
-        if (handles_.size() >= NUM_MAX_HANDLES) {
-            // Too many open files.
-            return -EMFILE;
-        }
-        uint32_t handle;
-        do {
-           handle = handle_counter_++;
-        } while (handles_.count(handle) != 0);
-        handles_.insert(std::make_pair(handle, header.nodeid));
-
-        out->prepare_buffer();
-        out->data()->fh = handle;
-        return 0;
-    }
-
-    int handle_fuse_read(const fuse_in_header& /* header */,
-                         const fuse_read_in* in,
-                         FuseResponse<void>* out) {
-        if (in->size > MAX_READ) {
-            return -EINVAL;
-        }
-        const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
-        if (it == handles_.end()) {
-            return -EBADF;
-        }
-        uint64_t offset = in->offset;
-        uint32_t size = in->size;
-
-        // Overwrite the size after writing data.
-        out->prepare_buffer(0);
-        const int64_t result = get_object_bytes(it->second, offset, size, out->data());
-        if (result < 0) {
-            return result;
-        }
-        out->set_size(result);
-        return 0;
-    }
-
-    int handle_fuse_write(const fuse_in_header& /* header */,
-                          const fuse_write_in* in,
-                          FuseResponse<fuse_write_out>* out) {
-        if (in->size > MAX_WRITE) {
-            return -EINVAL;
-        }
-        const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
-        if (it == handles_.end()) {
-            return -EBADF;
-        }
-        const uint64_t offset = in->offset;
-        const uint32_t size = in->size;
-        const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
-        uint32_t written_size;
-        const int result = write_object_bytes(
-                in->fh, it->second, offset, size, buffer, &written_size);
-        if (result < 0) {
-            return result;
-        }
-        out->prepare_buffer();
-        out->data()->size = written_size;
-        return 0;
-    }
-
-    int handle_fuse_release(const fuse_in_header& /* header */,
-                            const fuse_release_in* in,
-                            FuseResponse<void>* /* out */) {
-        handles_.erase(in->fh);
-        return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
-    }
-
-    int handle_fuse_flush(const fuse_in_header& /* header */,
-                          const fuse_flush_in* in,
-                          FuseResponse<void>* /* out */) {
-        return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
-    }
-
-    template <typename T, typename S>
-    void invoke_handler(int fd,
-                        FuseRequest* request,
-                        int (AppFuse::*handler)(const fuse_in_header&,
-                                                const T*,
-                                                FuseResponse<S>*)) {
-        FuseResponse<S> response(request->data());
-        const int reply_code = (this->*handler)(
-                request->header(),
-                static_cast<const T*>(request->data()),
-                &response);
-        fuse_reply(
-                fd,
-                request->header().unique,
-                reply_code,
-                request->data(),
-                response.size());
-    }
-
-    int64_t get_file_size(int inode) {
-        return static_cast<int64_t>(env_->CallLongMethod(
-                self_,
-                app_fuse_get_file_size,
-                static_cast<int>(inode)));
-    }
-
-    int64_t get_object_bytes(
-            int inode,
-            uint64_t offset,
-            uint32_t size,
-            void* buf) {
-        const jlong read_size = env_->CallLongMethod(
-                self_,
-                app_fuse_read_object_bytes,
-                static_cast<jint>(inode),
-                static_cast<jlong>(offset),
-                static_cast<jlong>(size));
-        if (read_size <= 0) {
-            return read_size;
-        }
-        ScopedLocalRef<jbyteArray> array(
-                env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
-        if (array.get() == nullptr) {
-            return -EFAULT;
-        }
-        ScopedByteArrayRO bytes(env_, array.get());
-        if (bytes.get() == nullptr) {
-            return -ENOMEM;
-        }
-        memcpy(buf, bytes.get(), read_size);
-        return read_size;
-    }
-
-    int write_object_bytes(uint64_t handle, int inode, uint64_t offset, uint32_t size,
-                           const void* buffer, uint32_t* written_size) {
-        static_assert(sizeof(uint64_t) <= sizeof(jlong),
-                      "jlong must be able to express any uint64_t values");
-        ScopedLocalRef<jbyteArray> array(
-                env_,
-                static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
-        {
-            ScopedByteArrayRW bytes(env_, array.get());
-            if (bytes.get() == nullptr) {
-                return -EIO;
-            }
-            memcpy(bytes.get(), buffer, size);
-        }
-        const int result = env_->CallIntMethod(
-                self_,
-                app_fuse_write_object_bytes,
-                file_handle_to_jlong(handle),
-                inode,
-                offset,
-                size,
-                array.get());
-        if (result < 0) {
-            return result;
-        }
-        *written_size = result;
-        return 0;
-    }
-
-    static jlong file_handle_to_jlong(uint64_t handle) {
-        static_assert(
-                sizeof(uint64_t) <= sizeof(jlong),
-                "jlong must be able to express any uint64_t values");
-        return static_cast<jlong>(handle);
-    }
-
-    static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
-                           size_t reply_size) {
-        // Don't send any data for error case.
-        if (reply_code != 0) {
-            reply_size = 0;
-        }
-
-        struct fuse_out_header hdr;
-        hdr.len = reply_size + sizeof(hdr);
-        hdr.error = reply_code;
-        hdr.unique = unique;
-
-        struct iovec vec[2];
-        vec[0].iov_base = &hdr;
-        vec[0].iov_len = sizeof(hdr);
-        vec[1].iov_base = reply_data;
-        vec[1].iov_len = reply_size;
-
-        const int res = writev(fd, vec, reply_size != 0 ? 2 : 1);
-        if (res < 0) {
-            ALOGE("*** REPLY FAILED *** %d\n", errno);
-        }
-    }
-};
-
-void com_android_mtp_AppFuse_start_app_fuse_loop(JNIEnv* env, jobject self, jint jfd) {
-    ScopedFd fd(static_cast<int>(jfd));
-    AppFuse appfuse(env, self);
-
-    ALOGV("Start fuse loop.");
-    while (true) {
-        FuseRequest request;
-
-        const ssize_t result = TEMP_FAILURE_RETRY(
-                read(fd, request.buffer, sizeof(request.buffer)));
-        if (result < 0) {
-            if (errno == ENODEV) {
-                ALOGV("AppFuse was unmounted.\n");
-                return;
-            }
-            ALOGE("Failed to read bytes from FD: errno=%d\n", errno);
-            continue;
-        }
-
-        const size_t length = static_cast<size_t>(result);
-        if (length < sizeof(struct fuse_in_header)) {
-            ALOGE("request too short: len=%zu\n", length);
-            continue;
-        }
-
-        if (request.header().len != length) {
-            ALOGE("malformed header: len=%zu, hdr->len=%u\n",
-                  length, request.header().len);
-            continue;
-        }
-
-        appfuse.handle_fuse_request(fd, &request);
-    }
-}
-
-static const JNINativeMethod gMethods[] = {
-    {
-        "native_start_app_fuse_loop",
-        "(I)V",
-        (void *) com_android_mtp_AppFuse_start_app_fuse_loop
-    }
-};
-
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
-    JNIEnv* env = nullptr;
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        ALOGE("ERROR: GetEnv failed\n");
-        return -1;
-
-    }
-    assert(env != nullptr);
-
-    jclass clazz = env->FindClass("com/android/mtp/AppFuse");
-    if (clazz == nullptr) {
-        ALOGE("Can't find com/android/mtp/AppFuse");
-        return -1;
-    }
-
-    app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
-    if (app_fuse_class == nullptr) {
-        ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
-        return -1;
-    }
-
-    app_fuse_get_file_size = env->GetMethodID(
-            app_fuse_class, "getFileSize", "(I)J");
-    if (app_fuse_get_file_size == nullptr) {
-        ALOGE("Can't find getFileSize");
-        return -1;
-    }
-
-    app_fuse_read_object_bytes = env->GetMethodID(
-            app_fuse_class, "readObjectBytes", "(IJJ)J");
-    if (app_fuse_read_object_bytes == nullptr) {
-        ALOGE("Can't find readObjectBytes");
-        return -1;
-    }
-
-    app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
-    if (app_fuse_write_object_bytes == nullptr) {
-        ALOGE("Can't find writeObjectBytes");
-        return -1;
-    }
-
-    app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
-    if (app_fuse_flush_file_handle == nullptr) {
-        ALOGE("Can't find flushFileHandle");
-        return -1;
-    }
-
-    app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
-    if (app_fuse_close_file_handle == nullptr) {
-        ALOGE("Can't find closeFileHandle");
-        return -1;
-    }
-
-    app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
-    if (app_fuse_buffer == nullptr) {
-        ALOGE("Can't find mBuffer");
-        return -1;
-    }
-
-    const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
-    if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
-        return -1;
-    }
-
-    const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
-    if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
-        return -1;
-    }
-
-    const int result = android::AndroidRuntime::registerNativeMethods(
-            env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
-    if (result < 0) {
-        return -1;
-    }
-
-    return JNI_VERSION_1_4;
-}
diff --git a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
index 0762571..36f6fe9 100644
--- a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
+++ b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.storage.StorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -36,38 +37,13 @@
 
 @RunWith(JUnit4.class)
 public class AppFusePerfTest {
+    final static int SIZE = 10 * 1024 * 1024;  // 10MB
+
     @Test
     @LargeTest
     public void testReadWriteFile() throws IOException {
         final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         final StorageManager storageManager = context.getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final int SIZE = 10 * 1024 * 1024;  // 10MB
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return SIZE;
-                    }
-
-                    @Override
-                    public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                            throws IOException {
-                        return size;
-                    }
-
-                    @Override
-                    public int writeObjectBytes(
-                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
-                        return size;
-                    }
-                });
-
-        appFuse.mount(storageManager);
 
         final byte[] bytes = new byte[SIZE];
         final int SAMPLES = 100;
@@ -75,22 +51,20 @@
         final double[] writeTime = new double[SAMPLES];
 
         for (int i = 0; i < SAMPLES; i++) {
-            final ParcelFileDescriptor fd = appFuse.openFile(
-                    INODE,
-                    ParcelFileDescriptor.MODE_READ_ONLY);
+            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+                    ParcelFileDescriptor.MODE_READ_ONLY, new TestCallback());
             try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                     new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
                 final long startTime = System.nanoTime();
                 stream.read(bytes);
                 readTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
             }
-
         }
 
         for (int i = 0; i < SAMPLES; i++) {
-            final ParcelFileDescriptor fd = appFuse.openFile(
-                    INODE,
-                    ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+                    ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE,
+                    new TestCallback());
             try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
                     new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
                 final long startTime = System.nanoTime();
@@ -99,8 +73,6 @@
             }
         }
 
-        appFuse.close();
-
         double readAverage = 0;
         double writeAverage = 0;
         double readSquaredAverage = 0;
@@ -127,28 +99,26 @@
         InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, results);
     }
 
-    private static class TestCallback implements AppFuse.Callback {
+    private static class TestCallback extends ProxyFileDescriptorCallback {
         @Override
-        public long getFileSize(int inode) throws FileNotFoundException {
-            throw new FileNotFoundException();
+        public long onGetSize() throws ErrnoException {
+            return SIZE;
         }
 
         @Override
-        public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
+        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+            return size;
         }
 
         @Override
-        public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
+        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+            return size;
         }
 
         @Override
-        public void flushFileHandle(long fileHandle) throws IOException {}
+        public void onFsync() throws ErrnoException {}
 
         @Override
-        public void closeFileHandle(long fileHandle) {}
+        public void onRelease() {}
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
deleted file mode 100644
index cd78e61..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ /dev/null
@@ -1,258 +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.mtp;
-
-import android.annotation.WorkerThread;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.storage.StorageManager;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.mtp.annotations.UsedByNative;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-public class AppFuse {
-    static {
-        System.loadLibrary("appfuse_jni");
-    }
-
-    private static final boolean DEBUG = false;
-
-    /**
-     * Max read amount specified at the FUSE kernel implementation.
-     * The value is copied from sdcard.c.
-     */
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    static final int MAX_READ = 128 * 1024;
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    static final int MAX_WRITE = 256 * 1024;
-
-    private final String mName;
-    private final Callback mCallback;
-
-    /**
-     * Buffer for read bytes request.
-     * Don't use the buffer from the out of AppFuseMessageThread.
-     */
-    private byte[] mBuffer = new byte[Math.max(MAX_READ, MAX_WRITE)];
-
-    private Thread mMessageThread;
-    private ParcelFileDescriptor mDeviceFd;
-
-    AppFuse(String name, Callback callback) {
-        mName = name;
-        mCallback = callback;
-    }
-
-    void mount(StorageManager storageManager) throws IOException {
-        Preconditions.checkState(mDeviceFd == null);
-        mDeviceFd = storageManager.mountAppFuse(mName);
-        mMessageThread = new AppFuseMessageThread(mDeviceFd.dup().detachFd());
-        mMessageThread.start();
-    }
-
-    @VisibleForTesting
-    void close() {
-        try {
-            // Remote side of ParcelFileDescriptor is tracking the close of mDeviceFd, and unmount
-            // the corresponding fuse file system. The mMessageThread will receive ENODEV, and
-            // then terminate itself.
-            mDeviceFd.close();
-            mMessageThread.join();
-        } catch (IOException exp) {
-            Log.e(MtpDocumentsProvider.TAG, "Failed to close device FD.", exp);
-        } catch (InterruptedException exp) {
-            Log.e(MtpDocumentsProvider.TAG, "Failed to terminate message thread.", exp);
-        }
-    }
-
-    /**
-     * Opens a file on app fuse and returns ParcelFileDescriptor.
-     *
-     * @param i ID for opened file.
-     * @param mode Mode for opening file.
-     * @see ParcelFileDescriptor#MODE_READ_ONLY
-     * @see ParcelFileDescriptor#MODE_WRITE_ONLY
-     */
-    public ParcelFileDescriptor openFile(int i, int mode) throws FileNotFoundException {
-        Preconditions.checkArgument(
-                mode == ParcelFileDescriptor.MODE_READ_ONLY ||
-                mode == (ParcelFileDescriptor.MODE_WRITE_ONLY |
-                         ParcelFileDescriptor.MODE_TRUNCATE));
-        return ParcelFileDescriptor.open(new File(
-                getMountPoint(),
-                Integer.toString(i)),
-                mode);
-    }
-
-    File getMountPoint() {
-        return new File("/mnt/appfuse/" + Process.myUid() + "_" + mName);
-    }
-
-    static interface Callback {
-        /**
-         * Returns file size for the given inode.
-         * @param inode
-         * @return File size. Must not be negative.
-         * @throws FileNotFoundException
-         */
-        long getFileSize(int inode) throws FileNotFoundException;
-
-        /**
-         * Returns file bytes for the give inode.
-         * @param inode
-         * @param offset Offset for file bytes.
-         * @param size Size for file bytes.
-         * @param bytes Buffer to store file bytes.
-         * @return Number of read bytes. Must not be negative.
-         * @throws IOException
-         */
-        long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
-
-        /**
-         * Handles writing bytes for the give inode.
-         * @param fileHandle
-         * @param inode
-         * @param offset Offset for file bytes.
-         * @param size Size for file bytes.
-         * @param bytes Buffer to store file bytes.
-         * @return Number of read bytes. Must not be negative.
-         * @throws IOException
-         */
-        int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException, ErrnoException;
-
-        /**
-         * Flushes bytes for file handle.
-         * @param fileHandle
-         * @throws IOException
-         * @throws ErrnoException
-         */
-        void flushFileHandle(long fileHandle) throws IOException, ErrnoException;
-
-        /**
-         * Closes file handle.
-         * @param fileHandle
-         * @throws IOException
-         */
-        void closeFileHandle(long fileHandle) throws IOException, ErrnoException;
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private long getFileSize(int inode) {
-        try {
-            return mCallback.getFileSize(inode);
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private long readObjectBytes(int inode, long offset, long size) {
-        if (offset < 0 || size < 0 || size > MAX_READ) {
-            return -OsConstants.EINVAL;
-        }
-        try {
-            // It's OK to share the same mBuffer among requests because the requests are processed
-            // by AppFuseMessageThread sequentially.
-            return mCallback.readObjectBytes(inode, offset, size, mBuffer);
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private /* unsgined */ int writeObjectBytes(long fileHandler,
-                                                int inode,
-                                                /* unsigned */ long offset,
-                                                /* unsigned */ int size,
-                                                byte[] bytes) {
-        try {
-            return mCallback.writeObjectBytes(fileHandler, inode, offset, size, bytes);
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private int flushFileHandle(long fileHandle) {
-        try {
-            mCallback.flushFileHandle(fileHandle);
-            return 0;
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private int closeFileHandle(long fileHandle) {
-        try {
-            mCallback.closeFileHandle(fileHandle);
-            return 0;
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    private static int getErrnoFromException(Exception error) {
-        if (DEBUG) {
-            Log.e(MtpDocumentsProvider.TAG, "AppFuse callbacks", error);
-        }
-        if (error instanceof FileNotFoundException) {
-            return OsConstants.ENOENT;
-        } else if (error instanceof IOException) {
-            return OsConstants.EIO;
-        } else if (error instanceof UnsupportedOperationException) {
-            return OsConstants.ENOTSUP;
-        } else if (error instanceof IllegalArgumentException) {
-            return OsConstants.EINVAL;
-        } else {
-            return OsConstants.EIO;
-        }
-    }
-
-    private native void native_start_app_fuse_loop(int fd);
-
-    private class AppFuseMessageThread extends Thread {
-        /**
-         * File descriptor used by native loop.
-         * It's owned by native loop and does not need to close here.
-         */
-        private final int mRawFd;
-
-        AppFuseMessageThread(int fd) {
-            super("AppFuseMessageThread");
-            mRawFd = fd;
-        }
-
-        @Override
-        public void run() {
-            native_start_app_fuse_loop(mRawFd);
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 6b2c1ee..8b0e610 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -33,6 +33,7 @@
 import android.os.CancellationSignal;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.storage.StorageManager;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Path;
@@ -41,6 +42,7 @@
 import android.provider.DocumentsProvider;
 import android.provider.Settings;
 import android.system.ErrnoException;
+import android.system.OsConstants;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -54,6 +56,8 @@
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 
+import libcore.io.IoUtils;
+
 /**
  * DocumentsProvider for MTP devices.
  */
@@ -84,9 +88,9 @@
     private RootScanner mRootScanner;
     private Resources mResources;
     private MtpDatabase mDatabase;
-    private AppFuse mAppFuse;
     private ServiceIntentSender mIntentSender;
     private Context mContext;
+    private StorageManager mStorageManager;
 
     /**
      * Provides singleton instance to MtpDocumentsService.
@@ -105,8 +109,8 @@
         mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
         mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE);
         mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
-        mAppFuse = new AppFuse(TAG, new AppFuseCallback());
         mIntentSender = new ServiceIntentSender(getContext());
+        mStorageManager = getContext().getSystemService(StorageManager.class);
 
         // Check boot count and cleans database if it's first time to launch MtpDocumentsProvider
         // after booting.
@@ -129,14 +133,6 @@
             return false;
         }
 
-        // TODO: Mount AppFuse on demands.
-        try {
-            mAppFuse.mount(getContext().getSystemService(StorageManager.class));
-        } catch (IOException error) {
-            Log.e(TAG, "Failed to start app fuse.", error);
-            return false;
-        }
-
         resume();
         return true;
     }
@@ -157,16 +153,9 @@
         mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
         mDatabase = database;
         mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
-        mAppFuse = new AppFuse(TAG, new AppFuseCallback());
         mIntentSender = intentSender;
+        mStorageManager = storageManager;
 
-        // TODO: Mount AppFuse on demands.
-        try {
-            mAppFuse.mount(storageManager);
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to start app fuse.", e);
-            return false;
-        }
         resume();
         return true;
     }
@@ -252,7 +241,10 @@
                 }
                 if (MtpDeviceRecord.isPartialReadSupported(
                         device.operationsSupported, fileSize)) {
-                    return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+
+                    return mStorageManager.openProxyFileDescriptor(
+                            modeFlag,
+                            new MtpProxyFileDescriptorCallback(Integer.parseInt(documentId)));
                 } else {
                     // If getPartialObject{|64} are not supported for the device, returns
                     // non-seekable pipe FD instead.
@@ -262,7 +254,9 @@
                 // TODO: Clear the parent document loader task (if exists) and call notify
                 // when writing is completed.
                 if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
-                    return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+                    return mStorageManager.openProxyFileDescriptor(
+                            modeFlag,
+                            new MtpProxyFileDescriptorCallback(Integer.parseInt(documentId)));
                 } else {
                     throw new UnsupportedOperationException(
                             "The device does not support writing operation.");
@@ -586,7 +580,6 @@
                 throw new RuntimeException(e);
             } finally {
                 mDatabase.close();
-                mAppFuse.close();
                 super.shutdown();
             }
         }
@@ -693,72 +686,92 @@
         }
     }
 
-    private class AppFuseCallback implements AppFuse.Callback {
-        private final Map<Long, MtpFileWriter> mWriters = new HashMap<>();
+    private class MtpProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
+        private final int mInode;
+        private MtpFileWriter mWriter;
 
-        @Override
-        public long getFileSize(int inode) throws FileNotFoundException {
-            return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
+        MtpProxyFileDescriptorCallback(int inode) {
+            mInode = inode;
         }
 
         @Override
-        public long readObjectBytes(
-                int inode, long offset, long size, byte[] buffer) throws IOException {
-            final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
-            final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
-
-            if (MtpDeviceRecord.isSupported(
-                    record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
-                return mMtpManager.getPartialObject64(
-                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
-            }
-
-            if (0 <= offset && offset <= 0xffffffffL && MtpDeviceRecord.isSupported(
-                    record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
-                return mMtpManager.getPartialObject(
-                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
-            }
-
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public int writeObjectBytes(
-                long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException, ErrnoException {
-            final MtpFileWriter writer;
-            if (mWriters.containsKey(fileHandle)) {
-                writer = mWriters.get(fileHandle);
-            } else {
-                writer = new MtpFileWriter(mContext, String.valueOf(inode));
-                mWriters.put(fileHandle, writer);
-            }
-            return writer.write(offset, size, bytes);
-        }
-
-        @Override
-        public void flushFileHandle(long fileHandle) throws IOException, ErrnoException {
-            final MtpFileWriter writer = mWriters.get(fileHandle);
-            if (writer == null) {
-                // File handle for reading.
-                return;
-            }
-            final MtpDeviceRecord device = getDeviceToolkit(
-                    mDatabase.createIdentifier(writer.getDocumentId()).mDeviceId).mDeviceRecord;
-            writer.flush(mMtpManager, mDatabase, device.operationsSupported);
-        }
-
-        @Override
-        public void closeFileHandle(long fileHandle) throws IOException, ErrnoException {
-            final MtpFileWriter writer = mWriters.get(fileHandle);
-            if (writer == null) {
-                // File handle for reading.
-                return;
-            }
+        public long onGetSize() throws ErrnoException {
             try {
-                writer.close();
+                return getFileSize(String.valueOf(mInode));
+            } catch (FileNotFoundException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onGetSize", OsConstants.ENOENT);
+            }
+        }
+
+        @Override
+        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+            try {
+                final Identifier identifier = mDatabase.createIdentifier(Integer.toString(mInode));
+                final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
+                if (MtpDeviceRecord.isSupported(
+                        record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
+
+                        return (int) mMtpManager.getPartialObject64(
+                                identifier.mDeviceId, identifier.mObjectHandle, offset, size, data);
+
+                }
+                if (0 <= offset && offset <= 0xffffffffL && MtpDeviceRecord.isSupported(
+                        record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
+                    return (int) mMtpManager.getPartialObject(
+                            identifier.mDeviceId, identifier.mObjectHandle, offset, size, data);
+                }
+                throw new ErrnoException("onRead", OsConstants.ENOTSUP);
+            } catch (IOException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onRead", OsConstants.EIO);
+            }
+        }
+
+        @Override
+        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+            try {
+                if (mWriter == null) {
+                    mWriter = new MtpFileWriter(mContext, String.valueOf(mInode));
+                }
+                return mWriter.write(offset, size, data);
+            } catch (IOException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onWrite", OsConstants.EIO);
+            }
+        }
+
+        @Override
+        public void onFsync() throws ErrnoException {
+            tryFsync();
+        }
+
+        @Override
+        public void onRelease() {
+            try {
+                tryFsync();
+            } catch (ErrnoException error) {
+                // Cannot recover from the error at onRelease. Client app should use fsync to
+                // ensure the provider writes data correctly.
+                Log.e(TAG, "Cannot recover from the error at onRelease.", error);
             } finally {
-                mWriters.remove(fileHandle);
+                if (mWriter != null) {
+                    IoUtils.closeQuietly(mWriter);
+                }
+            }
+        }
+
+        private void tryFsync() throws ErrnoException {
+            try {
+                if (mWriter != null) {
+                    final MtpDeviceRecord device =
+                            getDeviceToolkit(mDatabase.createIdentifier(
+                                    mWriter.getDocumentId()).mDeviceId).mDeviceRecord;
+                    mWriter.flush(mMtpManager, mDatabase, device.operationsSupported);
+                }
+            } catch (IOException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onWrite", OsConstants.EIO);
             }
         }
     }
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
index 8538379..e50d6fb 100644
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ b/packages/MtpDocumentsProvider/tests/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
 LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
deleted file mode 100644
index e421de7..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ /dev/null
@@ -1,262 +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.mtp;
-
-import android.os.ParcelFileDescriptor;
-import android.os.storage.StorageManager;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Arrays;
-
-@MediumTest
-public class AppFuseTest extends AndroidTestCase {
-    public void testMount() throws ErrnoException, IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final AppFuse appFuse = new AppFuse("test", new TestCallback());
-        appFuse.mount(storageManager);
-        final File file = appFuse.getMountPoint();
-        assertTrue(file.isDirectory());
-        assertEquals(1, Os.stat(file.getPath()).st_ino);
-        appFuse.close();
-        assertTrue(1 != Os.stat(file.getPath()).st_ino);
-    }
-
-    public void testOpenFile() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (INODE == inode) {
-                            return 1024;
-                        }
-                        throw new FileNotFoundException();
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_READ_ONLY);
-        fd.close();
-        appFuse.close();
-    }
-
-    public void testOpenFile_fileNotFound() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse("test", new TestCallback());
-        appFuse.mount(storageManager);
-        try {
-            appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_ONLY);
-            fail();
-        } catch (FileNotFoundException exp) {}
-        appFuse.close();
-    }
-
-    public void testOpenFile_illegalMode() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse("test", new TestCallback());
-        appFuse.mount(storageManager);
-        try {
-            appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_WRITE);
-            fail();
-        } catch (IllegalArgumentException exp) {}
-        appFuse.close();
-    }
-
-    public void testReadFile() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int fileInode = 10;
-        final byte[] fileBytes = new byte[] { 'a', 'b', 'c', 'd', 'e' };
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode == fileInode) {
-                            return fileBytes.length;
-                        }
-                        return super.getFileSize(inode);
-                    }
-
-                    @Override
-                    public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                            throws IOException {
-                        if (inode == fileInode) {
-                            int i = 0;
-                            while (i < size && i + offset < fileBytes.length)  {
-                                bytes[i] = fileBytes[(int) (i + offset)];
-                                i++;
-                            }
-                            return i;
-                        }
-                        return super.readObjectBytes(inode, offset, size, bytes);
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                fileInode, ParcelFileDescriptor.MODE_READ_ONLY);
-        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
-                new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
-            final byte[] buffer = new byte[1024];
-            final int size = stream.read(buffer, 0, buffer.length);
-            assertEquals(5, size);
-        }
-        appFuse.close();
-    }
-
-    public void testWriteFile() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final byte[] resultBytes = new byte[5];
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return resultBytes.length;
-                    }
-
-                    @Override
-                    public int writeObjectBytes(
-                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
-                        for (int i = 0; i < size; i++) {
-                            resultBytes[(int)(offset + i)] = bytes[i];
-                        }
-                        return size;
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-            stream.write('a');
-            stream.write('b');
-            stream.write('c');
-            stream.write('d');
-            stream.write('e');
-        }
-        final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
-        assertTrue(Arrays.equals(BYTES, resultBytes));
-        appFuse.close();
-    }
-
-    public void testWriteFile_writeError() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return 5;
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-            stream.write('a');
-            fail();
-        } catch (IOException e) {
-        }
-        appFuse.close();
-    }
-
-    public void testWriteFile_flushError() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return 5;
-                    }
-
-                    @Override
-                    public int writeObjectBytes(
-                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
-                        return size;
-                    }
-
-                    @Override
-                    public void flushFileHandle(long fileHandle) throws IOException {
-                        throw new IOException();
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-            stream.write('a');
-            try {
-                IoUtils.close(fd.getFileDescriptor());
-                fail();
-            } catch (IOException e) {
-            }
-        }
-        appFuse.close();
-    }
-
-    private static class TestCallback implements AppFuse.Callback {
-        @Override
-        public long getFileSize(int inode) throws FileNotFoundException {
-            throw new FileNotFoundException();
-        }
-
-        @Override
-        public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
-        }
-
-        @Override
-        public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
-        }
-
-        @Override
-        public void flushFileHandle(long fileHandle) throws IOException {}
-
-        @Override
-        public void closeFileHandle(long fileHandle) {}
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index a9d35e1..491e24d 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -557,6 +557,7 @@
             try (ParcelFileDescriptor.AutoCloseOutputStream stream =
                     new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
                 stream.write("Hello".getBytes());
+                fd.getFileDescriptor().sync();
             }
         }
         {
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index d108c20..f36167e 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -26,10 +26,10 @@
     <string name="label_color" msgid="1108690305218188969">"रंग"</string>
     <string name="label_duplex" msgid="5370037254347072243">"दो-तरफ़ा"</string>
     <string name="label_orientation" msgid="2853142581990496477">"अभिविन्‍यास"</string>
-    <string name="label_pages" msgid="7768589729282182230">"पृष्ठ"</string>
+    <string name="label_pages" msgid="7768589729282182230">"पेज"</string>
     <string name="destination_default_text" msgid="5422708056807065710">"कोई प्रिंटर चुनें"</string>
     <string name="template_all_pages" msgid="3322235982020148762">"सभी <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
-    <string name="template_page_range" msgid="428638530038286328">"पृष्ठ संख्या <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+    <string name="template_page_range" msgid="428638530038286328">"पेज संख्या <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
     <string name="pages_range_example" msgid="8558694453556945172">"उदा. 1—5,8,11—13"</string>
     <string name="print_preview" msgid="8010217796057763343">"प्रिंट पूर्वावलोकन"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"पूर्वावलोकन के लिए PDF व्यूअर इंस्टॉल करें"</string>
@@ -39,7 +39,7 @@
     <string name="all_printers" msgid="5018829726861876202">"सभी प्रिंटर..."</string>
     <string name="print_dialog" msgid="32628687461331979">"प्रिंट डॉयलॉग"</string>
     <string name="current_page_template" msgid="5145005201131935302">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
-    <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g> में से पृष्ठ <xliff:g id="CURRENT_PAGE">%1$d</xliff:g>"</string>
+    <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="PAGE_COUNT">%2$d</xliff:g> में से पेज <xliff:g id="CURRENT_PAGE">%1$d</xliff:g>"</string>
     <string name="summary_template" msgid="8899734908625669193">"सारांश, प्रतियां <xliff:g id="COPIES">%1$s</xliff:g>, काग़ज़ का आकार <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
     <string name="expand_handle" msgid="7282974448109280522">"हैंडल विस्तृत करें"</string>
     <string name="collapse_handle" msgid="6886637989442507451">"हैंडल संक्षिप्त करें"</string>
diff --git a/packages/SettingsLib/Android.mk b/packages/SettingsLib/Android.mk
index ad07283..67ef40a 100644
--- a/packages/SettingsLib/Android.mk
+++ b/packages/SettingsLib/Android.mk
@@ -12,6 +12,8 @@
     android-support-v7-appcompat \
     android-support-v14-preference
 
+LOCAL_STATIC_JAVA_LIBRARY := legacy-android-test
+
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
 LOCAL_JAR_EXCLUDE_FILES := none
@@ -21,4 +23,4 @@
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 # For the test package.
-include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml b/packages/SettingsLib/res/layout/access_point_friction_widget.xml
similarity index 62%
copy from packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
copy to packages/SettingsLib/res/layout/access_point_friction_widget.xml
index 387ca29..7409686 100644
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
+++ b/packages/SettingsLib/res/layout/access_point_friction_widget.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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,11 +13,10 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/friction_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:contentDescription="@null" />
diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index 24a5422..b659cee 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -26,12 +26,12 @@
         android:orientation="vertical"
         android:fitsSystemWindows="true">
         <FrameLayout
+            style="?android:attr/actionBarStyle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:theme="?android:attr/actionBarTheme">
             <Toolbar
                 android:id="@+id/action_bar"
-                style="?android:attr/actionBarStyle"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:navigationContentDescription="@*android:string/action_bar_up_description"/>
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index 4cb349c..b120ffe 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Gebruik HDCP-kontrolering net vir DRM-inhoud"</item>
     <item msgid="45075631231212732">"Gebruik altyd HDCP-kontrolering"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Verstek"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Verstek"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Verstek"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Verstek"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Verstek"</item>
-    <item msgid="5618929009984956469">"16 bis per voorbeeld"</item>
-    <item msgid="3412640499234627248">"24 bis per voorbeeld"</item>
-    <item msgid="121583001492929387">"32 bis per voorbeeld"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Verstek"</item>
-    <item msgid="4726688794884191540">"16 bis per voorbeeld"</item>
-    <item msgid="305344756485516870">"24 bis per voorbeeld"</item>
-    <item msgid="244568657919675099">"32 bis per voorbeeld"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Verstek"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Verstek"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Klankgehalte verkies (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standaard (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Verbinding verkies (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Klankgehalte verkies (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standaard (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Verbinding verkies (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Af"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 3672fa9..63fa08c 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Sellulêre data altyd aktief"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiveer absolute volume"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-oudiokodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Kies Bluetooth-A2DP-kodek wat verkies word"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth-oudiovoorbeeldkoers"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Kies Bluetooth-A2DP-kodekvoorbeeldkoers wat verkies word"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-oudiobisse per voorbeeld"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Kies die Bluetooth-A2DP-kodekbisse per voorbeeld wat verkies word"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth-oudiokanaalmodus"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Kies Bluetooth-A2DP-kodekkanaalmodus wat verkies word"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth-oudio-LDAC-speelgehalte"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Kies Bluetooth-A2DP-kodek-LDAC-speelgehalte wat verkies word"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Wys opsies vir draadlose skermsertifisering"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Verhoog Wi-Fi-aantekeningvlak, wys per SSID RSSI in Wi‑Fi-kieser"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wanneer dit geaktiveer is, sal Wi-Fi meer aggressief wees om die dataverbinding na selfoon oor te dra wanneer die Wi-Fi-sein swak is"</string>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 0b424b3..5f35d32 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"ለDRM ይዘት ብቻ HDCP  ምልከታን ተጠቀም"</item>
     <item msgid="45075631231212732">"ሁልጊዜ የHDCP ምልከታ ተጠቀም"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ነባሪ"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ነባሪ"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ነባሪ"</item>
-    <item msgid="8895532488906185219">"44.1 ኪኸ"</item>
-    <item msgid="2909915718994807056">"48.0 ኪኸ"</item>
-    <item msgid="3347287377354164611">"88.2 ኪኸ"</item>
-    <item msgid="1234212100239985373">"96.0 ኪኸ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ነባሪ"</item>
-    <item msgid="4482862757811638365">"44.1 ኪኸ"</item>
-    <item msgid="354495328188724404">"48.0 ኪኸ"</item>
-    <item msgid="7329816882213695083">"88.2 ኪኸ"</item>
-    <item msgid="6967397666254430476">"96.0 ኪኸ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ነባሪ"</item>
-    <item msgid="5618929009984956469">"16 ቢት/ናሙና"</item>
-    <item msgid="3412640499234627248">"24 ቢት/ናሙና"</item>
-    <item msgid="121583001492929387">"32 ቢት/ናሙና"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ነባሪ"</item>
-    <item msgid="4726688794884191540">"16 ቢት/ናሙና"</item>
-    <item msgid="305344756485516870">"24 ቢት/ናሙና"</item>
-    <item msgid="244568657919675099">"32 ቢት/ናሙና"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ነባሪ"</item>
-    <item msgid="4106832974775067314">"ሞኖ"</item>
-    <item msgid="5571632958424639155">"ስቲሪዮ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ነባሪ"</item>
-    <item msgid="8900559293912978337">"ሞኖ"</item>
-    <item msgid="8883739882299884241">"ስቲሪዮ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"የሚመረጠው የድምጽ ጥራት (990ኪቢ/ሴ/909ኪቢ/ሴ)"</item>
-    <item msgid="138837449700903545">"መደበኛ (660ኪቢ/ሴ/606ኪቢ/ሴ)"</item>
-    <item msgid="4777177307869441982">"የሚመረጠው ግንኙነት (330ኪቢ/ሴ/303ኪቢ/ሴ)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"የሚመረጠው የድምጽ ጥራት (990ኪቢ/ሴ/909ኪቢ/ሴ)"</item>
-    <item msgid="9091111147684472529">"መደበኛ (660ኪቢ/ሴ/606ኪቢ/ሴ)"</item>
-    <item msgid="3367904477834831032">"የሚመረጠው ግንኙነት (330ኪቢ/ሴ/303ኪቢ/ሴ)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ጠፍቷል"</item>
     <item msgid="1593289376502312923">"64 ኪባ"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 42783ec..8ecef6e 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"የተንቀስቃሽ ስልክ ውሂብ ሁልጊዜ ንቁ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ፍጹማዊ ድምፅን አሰናክል"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"የብሉቱዝ ኦዲዮ ኮዴክ"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"የሚመረጠውን የብሉቱዝ A2DP ኮዴክ ምረጥ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"የብሉቱዝ ኦዲዮ ናሙና ፍጥነት"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"የሚመረጠውን የብሉቱዝ A2DP ኮዴክ ናሙና ፍጥነት ምረጥ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"የብሉቱዝ ኦዲዮ ቢት በናሙና"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"የሚመረጠውን የብሉቱዝ A2DP ኮዴክ ቢት በናሙና ምረጥ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"የብሉቱዝ ኦዲዮ ሰርጥ ሁነታ"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"የሚመረጠውን የብሉቱዝ A2DP ኮዴክ ሰርጥ ሁነታ ምረጥ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"የብሉቱዝ ኦዲዮ LDAC መልሶ ማጫወት ጥራት"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"የሚመረጠውን የብሉቱዝ A2DP ኮዴክ LDAC መልሶ ማጫወት ጥራት ይምረጡ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"የገመድ አልባ ማሳያ እውቅና ማረጋገጫ አማራጮችን አሳይ"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"የWi‑Fi ምዝግብ ማስታወሻ አያያዝ ደረጃ ጨምር፣ በWi‑Fi መምረጫ ውስጥ በአንድ SSID RSSI አሳይ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ሲነቃ የWi‑Fi ምልክት ዝቅተኛ ሲሆን Wi‑Fi የውሂብ ግንኙነት ለተንቀሳቃሽ ማስረከብ ላይ ይበልጥ አስገዳጅ ይሆናል"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index ae61f64..f7f771a 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"‏استخدام التحقق من HDCP لمحتوى DRM فقط"</item>
     <item msgid="45075631231212732">"‏استخدام التحقق من HDCP دومًا"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"افتراضي"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"افتراضي"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"افتراضي"</item>
-    <item msgid="8895532488906185219">"44.1 كيلو هرتز"</item>
-    <item msgid="2909915718994807056">"48.0 كيلو هرتز"</item>
-    <item msgid="3347287377354164611">"88.2 كيلو هرتز"</item>
-    <item msgid="1234212100239985373">"96.0 كيلو هرتز"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"افتراضي"</item>
-    <item msgid="4482862757811638365">"44.1 كيلو هرتز"</item>
-    <item msgid="354495328188724404">"48.0 كيلو هرتز"</item>
-    <item msgid="7329816882213695083">"88.2 كيلو هرتز"</item>
-    <item msgid="6967397666254430476">"96.0 كيلو هرتز"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"افتراضي"</item>
-    <item msgid="5618929009984956469">"16 بت لكل عيّنة"</item>
-    <item msgid="3412640499234627248">"24 بت لكل عيّنة"</item>
-    <item msgid="121583001492929387">"32 بت لكل عيّنة"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"افتراضي"</item>
-    <item msgid="4726688794884191540">"16 بت لكل عيّنة"</item>
-    <item msgid="305344756485516870">"24 بت لكل عيّنة"</item>
-    <item msgid="244568657919675099">"32 بت لكل عيّنة"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"افتراضي"</item>
-    <item msgid="4106832974775067314">"أحادي"</item>
-    <item msgid="5571632958424639155">"استريو"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"افتراضي"</item>
-    <item msgid="8900559293912978337">"أحادي"</item>
-    <item msgid="8883739882299884241">"استريو"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"جودة الصوت المفضّلة (990/909 كيلوبت في الثانية)"</item>
-    <item msgid="138837449700903545">"قياسي (660/606 كيلوبت في الثانية)"</item>
-    <item msgid="4777177307869441982">"الاتصال المفضّل (330/303 كيلوبت في الثانية)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"جودة الصوت المفضّلة (990/909 كيلوبت في الثانية)"</item>
-    <item msgid="9091111147684472529">"قياسي (660/606 كيلوبت في الثانية)"</item>
-    <item msgid="3367904477834831032">"الاتصال المفضّل (330/303 كيلوبت في الثانية)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"إيقاف"</item>
     <item msgid="1593289376502312923">"٦٤ كيلوبايت"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e1b39c11..4a1e916 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"بيانات الجوّال نشطة دائمًا"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"تعطيل مستوى الصوت المطلق"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ترميز صوت بلوتوث"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"‏حدّد ترميز بلوتوث A2DP المفضّل"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"معدّل عيّنة صوت بلوتوث"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"‏حدّد معدّل عيّنة ترميز A2DP بلوتوث المفضّل"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"وحدات البت لكل عيّنة في صوت بلوتوث"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"‏حدّد عدد وحدات البت لكل عيّنة المفضّل في ترميز بلوتوث A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"وضع قناة صوت بلوتوث"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"‏حدّد وضع القناة المفضّل في ترميز بلوتوث A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"‏جودة تشغيل صوت بلوتوث LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"‏حدّد جودة التشغيل المفضّلة في ترميز بلوتوث A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"عرض خيارات شهادة عرض شاشة لاسلكي"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏زيادة مستوى تسجيل Wi-Fi، وعرض لكل SSID RSSI في منتقي Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏عند تمكينه، سيكون Wi-Fi أكثر حدة في تسليم اتصال البيانات إلى الشبكة الخلوية، وذلك عندما تكون إشارة WiFi منخفضة"</string>
diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml
index 38b2dc0..9ad0c28 100644
--- a/packages/SettingsLib/res/values-az/arrays.xml
+++ b/packages/SettingsLib/res/values-az/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Yalnız DRM məzmun oxumaq üçün HDCP istifadə edin"</item>
     <item msgid="45075631231212732">"Həmişə HDCP yoxlama istifadə edin"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Defolt"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Defolt"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Defolt"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Defolt"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Defolt"</item>
-    <item msgid="5618929009984956469">"16 bit/nümunə"</item>
-    <item msgid="3412640499234627248">"24 bit/nümunə"</item>
-    <item msgid="121583001492929387">"32 bit/nümunə"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Defolt"</item>
-    <item msgid="4726688794884191540">"16 bit/nümunə"</item>
-    <item msgid="305344756485516870">"24 bit/nümunə"</item>
-    <item msgid="244568657919675099">"32 bit/nümunə"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Defolt"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Defolt"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Səs keyfiyyəti tərcih edildi (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standart (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Bağlantı tərcih edildi (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Səs keyfiyyəti tərcih edildi (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standart (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Bağlantı tərcih edildi (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Deaktiv"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index e625e32..ac854c6 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobil data həmişə aktivdir"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mütləq səs həcmi deaktiv edin"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Tərcih edilmiş Bluetooth A2DP Kodek seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Nümunə Göstəricisi"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Tərcih edilmiş Bluetooth A2DP Kodek Nümunə Göstəricisi seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Hər Nümunə Üçün Bluetooth Audio Bit"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Hər nümunə üçün tərcih edilmiş Bluetooth A2DP Kodek Bit seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Kanal Rejimi"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Tərcih edilmiş Bluetooth A2DP Kodek Kanal Rejimi seçin"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Audio LDAC Oxutma Keyfiyyəti"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Tərcih edilmiş Bluetooth A2DP Kodek LDAC Oxutma Keyfiyyəti seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz displey sertifikatlaşması üçün seçimləri göstərir"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi giriş səviyyəsini qaldırın, Wi‑Fi seçəndə hər SSID RSSI üzrə göstərin"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Aktiv olanda, Wi‑Fi sianqlı zəif olan zaman, Mobil şəbəkə data bağlantısına nisbətən, Wi‑Fi daha aqressiv olacaq"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
index 9f7cf56..bde7f58 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Koristi HDCP proveru samo za DRM sadržaj"</item>
     <item msgid="45075631231212732">"Uvek koristi HDCP proveru"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Podrazumevano"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Podrazumevano"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Podrazumevano"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Podrazumevano"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Podrazumevano"</item>
-    <item msgid="5618929009984956469">"16 bitova po uzorku"</item>
-    <item msgid="3412640499234627248">"24 bita po uzorku"</item>
-    <item msgid="121583001492929387">"32 bita po uzorku"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Podrazumevano"</item>
-    <item msgid="4726688794884191540">"16 bitova po uzorku"</item>
-    <item msgid="305344756485516870">"24 bita po uzorku"</item>
-    <item msgid="244568657919675099">"32 bita po uzorku"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Podrazumevano"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Podrazumevano"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Željeni kvalitet zvuka (990 kb/s/909 kb/s)"</item>
-    <item msgid="138837449700903545">"Standardno (660 kb/s/606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Željena veza (330 kb/s/303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Željeni kvalitet zvuka (990 kb/s/909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Standardno (660 kb/s/606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Željena veza (330 kb/s/303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Isključeno"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3446a1a..62be8b2 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Podaci za mobilne uređaje su uvek aktivni"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući glavno podešavanje jačine zvuka"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Izaberite željeni Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorkovanja za Bluetooth audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Izaberite željenu brzinu uzorkovanja za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bitova po uzorku za Bluetooth audio"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Izaberite željeni broj bitova po uzorku za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Režim kanala za Bluetooth audio"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Izaberite željeni režim kanala za Bluetooth A2DP kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Kvalitet LDAC snimka za Bluetooth audio"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Izaberite željeni kvalitet LDAC snimka za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada se omogući, Wi‑Fi će biti agresivniji pri prebacivanju mreže za prenos podataka na Mobilnu, kada je Wi‑Fi signal slab"</string>
diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml
index 1266d2c..50842cf 100644
--- a/packages/SettingsLib/res/values-be/arrays.xml
+++ b/packages/SettingsLib/res/values-be/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Выкарыстанне праверкі HDCP только для змесціва, абароненага DRM"</item>
     <item msgid="45075631231212732">"Заўсёды выкарыстоўваць праверку HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Стандартная"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Стандартная"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Стандартная"</item>
-    <item msgid="8895532488906185219">"44,1 кГц"</item>
-    <item msgid="2909915718994807056">"48,0 кГц"</item>
-    <item msgid="3347287377354164611">"88,2 кГц"</item>
-    <item msgid="1234212100239985373">"96,0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Стандартная"</item>
-    <item msgid="4482862757811638365">"44,1 кГц"</item>
-    <item msgid="354495328188724404">"48,0 кГц"</item>
-    <item msgid="7329816882213695083">"88,2 кГц"</item>
-    <item msgid="6967397666254430476">"96,0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Стандартная"</item>
-    <item msgid="5618929009984956469">"16 бітаў/сэмпл"</item>
-    <item msgid="3412640499234627248">"24 біты/сэмпл"</item>
-    <item msgid="121583001492929387">"32 біты/сэмпл"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Стандартная"</item>
-    <item msgid="4726688794884191540">"16 бітаў/сэмпл"</item>
-    <item msgid="305344756485516870">"24 біты/сэмпл"</item>
-    <item msgid="244568657919675099">"32 біты/сэмпл"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Стандартная"</item>
-    <item msgid="4106832974775067314">"Мона"</item>
-    <item msgid="5571632958424639155">"Стэрэа"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Стандартная"</item>
-    <item msgid="8900559293912978337">"Мона"</item>
-    <item msgid="8883739882299884241">"Стэрэа"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Прыярытэтная якасць гуч. (990/909кбіт/с)"</item>
-    <item msgid="138837449700903545">"Стандартная (660/606кбіт/с)"</item>
-    <item msgid="4777177307869441982">"Прыярытэтнае падключэнне (330/303кбіт/с)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Прыярытэтная якасць гуч. (990/909кбіт/с)"</item>
-    <item msgid="9091111147684472529">"Стандартная (660/606кбіт/с)"</item>
-    <item msgid="3367904477834831032">"Прыярытэтнае падключэнне (330/303кбіт/с)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Выкл."</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f2e1cf6..f50253b 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Перадача даных мабільнай сувязі заўсёды актыўна"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Адключыць абсалютны гук"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодэк Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Выберыце прыярытэтны кодэк Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Частата дыскрэтызацыі Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Выберыце прыярытэтную частату дыскрэтызацыі для кодэка Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Біты на сэмпл для Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Выберыце прыярытэтную колькасць бітаў на сэмпл для кодэка Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Канальны рэжым Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Выберыце прыярытэтны рэжым для кодэка Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Якасць прайгравання для Bluetooth Audio LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Выберыце прыярытэтную якасць прайгравання для кодэка Bluetooth A2DP LDAC"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Паказаць опцыі сертыфікацыі бесправаднога дысплея"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Падвыс. узровень дэтал-цыі журнала Wi‑Fi у залежн. ад SSID RSSI у Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Калі ўкл., прылада будзе больш інтэнсіўна імкнуцца перайсці з падлуч. да Wi-Fi на падлуч. да маб. сеткі, калі сігнал Wi‑Fi слабы"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index d220a07..c97e5f5 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Да се използва проверка с HDCP само за DRM съдържание"</item>
     <item msgid="45075631231212732">"Винаги да се използва проверка с HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Стандартно"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Стандартно"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Стандартно"</item>
-    <item msgid="8895532488906185219">"44,1 кХц"</item>
-    <item msgid="2909915718994807056">"48 кХц"</item>
-    <item msgid="3347287377354164611">"88,2 кХц"</item>
-    <item msgid="1234212100239985373">"96 кХц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Стандартно"</item>
-    <item msgid="4482862757811638365">"44,1 кХц"</item>
-    <item msgid="354495328188724404">"48 кХц"</item>
-    <item msgid="7329816882213695083">"88,2 кХц"</item>
-    <item msgid="6967397666254430476">"96 кХц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Стандартно"</item>
-    <item msgid="5618929009984956469">"16 бита/дискрет"</item>
-    <item msgid="3412640499234627248">"24 бита/дискрет"</item>
-    <item msgid="121583001492929387">"32 бита/дискрет"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Стандартно"</item>
-    <item msgid="4726688794884191540">"16 бита/дискрет"</item>
-    <item msgid="305344756485516870">"24 бита/дискрет"</item>
-    <item msgid="244568657919675099">"32 бита/дискрет"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Стандартно"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Стандартно"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Предпоч. кач. на звука (990 или 909 кб/сек)"</item>
-    <item msgid="138837449700903545">"Стандартно (660 или 606 кб/сек)"</item>
-    <item msgid="4777177307869441982">"Предпоч. връзка (330 или 303 кб/сек)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Предпоч. кач. на звука (990 или 909 кб/сек)"</item>
-    <item msgid="9091111147684472529">"Стандартно (660 или 606 кб/сек)"</item>
-    <item msgid="3367904477834831032">"Предпоч. връзка (330 или 303 кб/сек)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Изключено"</item>
     <item msgid="1593289376502312923">"64 КБ"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 21d1a98..c0d43b2 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Винаги активни клетъчни данни"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Деактивиране на пълната сила на звука"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Аудиокодек за Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Изберете предпочитания кодек за Bluetooth с профил A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Честота на дискретизация за звука през Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Изберете предпочитаната честота на дискретизация за кодека за Bluetooth с профил A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Битове на дискрет за звука през Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Изберете предпочитание за битове на дискрет за кодека за Bluetooth с профил A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим на канала на звука през Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Изберете предпочитания режим на канала за кодека за Bluetooth с профил A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Качество на възпроизвеждане на звука през Bluetooth с технологията LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Изберете предпочитаното качество на възпроизвеждане с технологията LDAC за кодека за Bluetooth с профил A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показване на опциите за сертифициране на безжичния дисплей"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"По-подробно регистр. на Wi‑Fi – данни за RSSI на SSID в инстр. за избор на Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"При активиране предаването на връзката за данни от Wi-Fi към мобилната мрежа ще е по-агресивно, когато Wi-Fi сигналът е слаб"</string>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index 6ce7b14..faea551 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"শুধুমাত্র DRM সামগ্রীর জন্য HDCP চেক করা ব্যবহার করুন"</item>
     <item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ডিফল্ট"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ডিফল্ট"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ডিফল্ট"</item>
-    <item msgid="8895532488906185219">"৪৪.১ kHz"</item>
-    <item msgid="2909915718994807056">"৪৮.০ kHz"</item>
-    <item msgid="3347287377354164611">"৮৮.২ kHz"</item>
-    <item msgid="1234212100239985373">"৯৬.০ kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ডিফল্ট"</item>
-    <item msgid="4482862757811638365">"৪৪.১ kHz"</item>
-    <item msgid="354495328188724404">"৪৮.০ kHz"</item>
-    <item msgid="7329816882213695083">"৮৮.২ kHz"</item>
-    <item msgid="6967397666254430476">"৯৬.০ kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ডিফল্ট"</item>
-    <item msgid="5618929009984956469">"১৬ বিট/নমুনা"</item>
-    <item msgid="3412640499234627248">"২৪ বিট/নমুনা"</item>
-    <item msgid="121583001492929387">"৩২ বিট/নমুনা"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ডিফল্ট"</item>
-    <item msgid="4726688794884191540">"১৬ বিট/নমুনা"</item>
-    <item msgid="305344756485516870">"২৪ বিট/নমুনা"</item>
-    <item msgid="244568657919675099">"৩২ বিট/নমুনা"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ডিফল্ট"</item>
-    <item msgid="4106832974775067314">"মোনো"</item>
-    <item msgid="5571632958424639155">"স্টিরিও"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ডিফল্ট"</item>
-    <item msgid="8900559293912978337">"মোনো"</item>
-    <item msgid="8883739882299884241">"স্টিরিও"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"পছন্দের শব্দের মান (৯৯০kbps/৯০৯kbps)"</item>
-    <item msgid="138837449700903545">"মানক (৬৬০kbps/৬০৬kbps)"</item>
-    <item msgid="4777177307869441982">"পছন্দের সংযোগ (৩৩০kbps/৩০৩kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"পছন্দের শব্দের মান (৯৯০kbps/৯০৯kbps)"</item>
-    <item msgid="9091111147684472529">"মানক (৬৬০kbps/৬০৬kbps)"</item>
-    <item msgid="3367904477834831032">"পছন্দের সংযোগ (৩৩০kbps/৩০৩kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <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 66fa0673..380ee1c 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"সেলুলার ডেটা সর্বদাই সক্রিয় থাকে"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ব্লুটুথ অডিও কোডেক"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"পছন্দের ব্লুটুথ A2DP কোডেক বেছে নিন"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ব্লুটুথ অডিওর নমুনা হার"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"পছন্দের ব্লুটুথ A2DP কোডেক নমুনা হার বেছে নিন"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"নমুনা প্রতি ব্লুটুথ অডিও বিট"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"নমুনা প্রতি পছন্দের ব্লুটুথ A2DP কোডেক বিট বেছে নিন"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ব্লুটুথ অডিও চ্যানেল মোড"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"পছন্দের ব্লুটুথ A2DP কোডেক চ্যানেল মোড বেছে নিন"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ব্লুটুথ অডিও LDAC প্লেব্যাকের মান"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"পছন্দের ব্লুটুথ A2DP কোডেক LDAC প্লেব্যাকের মান বেছে নিন"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ওয়্যারলেস প্রদর্শন সার্টিফিকেশন জন্য বিকল্পগুলি দেখান"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ওয়াই-ফাই লগিং স্তর বাড়ান, ওয়াই-ফাই চয়নকারীতে SSID RSSI অনুযায়ী দেখান"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"সক্ষম করা থাকলে, নিম্নমানের ওয়াই-ফাই সিগন্যালের ক্ষেত্রে, সেলুলার-এ ডেটা সংযোগ প্রদান করতে ওয়াই-ফাই আরো বেশি শক্তিশালীভাবে কাজ করবে"</string>
diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml
index 93e0678..6c4cde3 100644
--- a/packages/SettingsLib/res/values-bs/arrays.xml
+++ b/packages/SettingsLib/res/values-bs/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Koristi HDCP provjeru samo za DRM sadržaj"</item>
     <item msgid="45075631231212732">"Uvijek koristi HDCP provjeru"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Podrazumijevano"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Podrazumijevano"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Zadano"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Zadano"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Podrazumijevano"</item>
-    <item msgid="5618929009984956469">"16 bitova/uzorak"</item>
-    <item msgid="3412640499234627248">"24 bitova/uzorak"</item>
-    <item msgid="121583001492929387">"32 bitova/uzorak"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Podrazumijevano"</item>
-    <item msgid="4726688794884191540">"16 bitova/uzorak"</item>
-    <item msgid="305344756485516870">"24 bitova/uzorak"</item>
-    <item msgid="244568657919675099">"32 bitova/uzorak"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Podrazumijevano"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Podrazumijevano"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Željena kvaliteta zvuka (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standardni (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Željena veza (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Željena kvaliteta zvuka (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standardni (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Željena veza (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Isključeno"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f2ae338..bb0e1b5 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogućite apsolutnu jačinu zvuka"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Izaberite željeni Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorkovanja za Bluetooth audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Izaberite željenu brzinu uzorkovanja za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio bitovi po uzorku"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Izaberite željeni broj bitova po uzorku za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način Bluetooth audio kanala"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Izaberite željeni način kanala Bluetooth A2DP kodeka"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Kvaliteta reprodukcije za Bluetooth Audio LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Izaberite željenu kvalitetu LDAC reprodukcije za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećajte nivo Wi-Fi zapisivanja, pokazati po SSID RSSI Wi-Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada je omogućeno, Wi-Fi će biti agresivniji u predavanju podatkovne veze mobilnoj, kada je Wi-Fi signal slab"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index 6cb4217..fb57ab4 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Utilitza la comprovació HDCP només per a contingut DRM"</item>
     <item msgid="45075631231212732">"Utilitza sempre la comprovació HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Predeterminat"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Predeterminat"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Predeterminat"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Predeterminat"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Predeterminat"</item>
-    <item msgid="5618929009984956469">"16 bits/mostra"</item>
-    <item msgid="3412640499234627248">"24 bits/mostra"</item>
-    <item msgid="121583001492929387">"32 bits/mostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Predeterminat"</item>
-    <item msgid="4726688794884191540">"16 bits/mostra"</item>
-    <item msgid="305344756485516870">"24 bits/mostra"</item>
-    <item msgid="244568657919675099">"32 bits/mostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Predeterminat"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Estèreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Predeterminat"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Estèreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qualitat del so preferida (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Estàndard (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Connexió preferida (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qualitat del so preferida (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Estàndard (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Connexió preferida (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <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-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index ad83d6b..4571e49 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dades mòbils sempre actives"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactiva el volum absolut"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Còdec d\'àudio per Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecciona el còdec Bluetooth A2DP preferit"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Velocitat de mostra d’àudio per Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecciona la velocitat de mostra preferida del còdec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits per mostra de l\'àudio per Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecciona els bits per mostra preferits del còdec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode de canal de l\'àudio per Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selecciona el mode de canal preferit del còdec Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualitat de reproducció LDAC de l\'àudio per Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selecciona la qualitat de reproducció LDAC preferida del còdec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra les opcions de certificació de pantalla sense fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Augmenta nivell de registre Wi‑Fi i mostra\'l per SSID RSSI al Selector de Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si s\'activa, la Wi-Fi serà més agressiva en transferir la connexió de dades al mòbil, si el senyal de la Wi-Fi no és estable"</string>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index bba5a16..8c96ac3 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Použít kontrolu HDCP pouze pro obsah DRM"</item>
     <item msgid="45075631231212732">"Vždy používat kontrolu HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Výchozí"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Výchozí"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Výchozí"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Výchozí"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Výchozí"</item>
-    <item msgid="5618929009984956469">"16 bitů / vzorek"</item>
-    <item msgid="3412640499234627248">"24 bitů / vzorek"</item>
-    <item msgid="121583001492929387">"32 bitů / vzorek"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Výchozí"</item>
-    <item msgid="4726688794884191540">"16 bitů / vzorek"</item>
-    <item msgid="305344756485516870">"24 bitů / vzorek"</item>
-    <item msgid="244568657919675099">"32 bitů / vzorek"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Výchozí"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Výchozí"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Přednost kvality zvuku (990 kb/s / 909 kb/s)"</item>
-    <item msgid="138837449700903545">"Standardní (660 kb/s / 606 kB/s)"</item>
-    <item msgid="4777177307869441982">"Přednost připojení (330 kb/s / 303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Přednost kvality zvuku (990 kb/s / 909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Standardní (660 kb/s / 606 kB/s)"</item>
-    <item msgid="3367904477834831032">"Přednost připojení (330 kb/s / 303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Vypnuto"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 706aa91..36017e2 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilní data jsou vždy aktivní"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázat absolutní hlasitost"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio – kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Vyberte preferovaný kodek Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio – vzorkovací frekvence"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Vybrat vzorkovací frekvenci pro preferovaný kodek Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio – počet bitů na vzorek"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Vybrat počet bitů na vzorek pro preferovaný kodek Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio – režim kanálu"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Vybrat režim kanálu pro preferovaný kodek Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Audio LDAC – kvalita přehrávání"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Vybrat kvalitu přehrávání pro preferovaný kodek Bluetooth A2DP LDAC"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobrazit možnosti certifikace bezdrátového displeje"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšit úroveň protokolování Wi‑Fi zobrazenou v SSID a RSSI při výběru sítě Wi‑Fi."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Pokud je tato možnost zapnuta, bude síť Wi-Fi agresivnější při předávání datového připojení mobilní síti při slabém signálu Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 6ae0aa8..1b54d4a 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Brug kun HDCP-kontrol ved DRM-indhold"</item>
     <item msgid="45075631231212732">"Brug altid HDCP-kontrol"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Standard"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Standard"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Standard"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Standard"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Standard"</item>
-    <item msgid="5618929009984956469">"16 bit pr. eksempel"</item>
-    <item msgid="3412640499234627248">"24 bit pr. eksempel"</item>
-    <item msgid="121583001492929387">"32 bit pr. eksempel"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Standard"</item>
-    <item msgid="4726688794884191540">"16 bit pr. eksempel"</item>
-    <item msgid="305344756485516870">"24 bit pr. eksempel"</item>
-    <item msgid="244568657919675099">"32 bit pr. eksempel"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Standard"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Standard"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Lydkvalitet foretrækkes (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Forbindelse foretrækkes (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Lydkvalitet foretrækkes (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Forbindelse foretrækkes (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Fra"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index c6e6fb7..2824b81 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata altid aktiveret"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiver absolut lydstyrke"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-lydcodec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Vælg foretrukken Bluetooth A2DP-codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Eksempelfrekvens for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Vælg eksempelfrekvens for foretrukken Bluetooth A2DP-codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit pr. eksempel for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Vælg bit pr. eksempel for foretrukken Bluetooth A2DP-codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanaltilstand for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Vælg kanaltilstand for foretrukken Bluetooth A2DP-codec"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"LDAC-afspilningskvalitet for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Vælg LDAC-afspilningskvalitet for foretrukken Bluetooth A2DP-codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis valgmuligheder for certificering af trådløs skærm"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øg mængden af Wi‑Fi-logføring. Vis opdelt efter SSID RSSI i Wi‑Fi-vælgeren"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Når dette er aktiveret, gennemtvinges en overdragelse af dataforbindelsen fra Wi-Fi til mobilnetværk, når Wi-Fi-signalet er svagt"</string>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index 935c2b4..796e58f 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP-Prüfung nur für DRM-Inhalte verwenden"</item>
     <item msgid="45075631231212732">"HDCP-Prüfung immer verwenden"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Standard"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Standard"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Standard"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Standard"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Standard"</item>
-    <item msgid="5618929009984956469">"16 Bits pro Sample"</item>
-    <item msgid="3412640499234627248">"24 Bits pro Sample"</item>
-    <item msgid="121583001492929387">"32 Bits pro Sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Standard"</item>
-    <item msgid="4726688794884191540">"16 Bits pro Sample"</item>
-    <item msgid="305344756485516870">"24 Bits pro Sample"</item>
-    <item msgid="244568657919675099">"32 Bits pro Sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Standard"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Standard"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Bevorzugte Tonqualität (990 kbit/s / 909 kbit/s)"</item>
-    <item msgid="138837449700903545">"Standard (660 kbit/s / 606 kbit/s)"</item>
-    <item msgid="4777177307869441982">"Bevorzugte Verbindung (330 kbit/s / 303 kbit/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Bevorzugte Tonqualität (990 kbit/s / 909 kbit/s)"</item>
-    <item msgid="9091111147684472529">"Standard (660 kbit/s / 606 kbit/s)"</item>
-    <item msgid="3367904477834831032">"Bevorzugte Verbindung (330 kbit/s / 303 kbit/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Aus"</item>
     <item msgid="1593289376502312923">"64.000"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 0ce1384..632866e 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile Datennutzung immer aktiviert"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Maximallautstärke deaktivieren"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-Audio-Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Bevorzugten Bluetooth-A2DP-Codec auwählen"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth-Audio-Abtastrate"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Bevorzugten Bluetooth-A2DP-Codec auswählen/Abtastrate"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-Audio/Bits pro Sample"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Bevorzugten Bluetooth-A2DP-Codec auswählen/Bits Pro Sample"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modus des Bluetooth-Audiokanals"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Bevorzugten Bluetooth-A2DP-Codec auswählen/Modus des Kanals"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"LDAC-Wiedergabequalität von Bluetooth-Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Bevorzugten Bluetooth-A2DP-Codec auswählen/LDAC-Wiedergabequalität"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Optionen zur Zertifizierung für kabellose Übertragung anzeigen"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Level für WLAN-Protokollierung erhöhen, in WiFi Picker pro SSID-RSSI anzeigen"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wenn diese Option aktiviert ist, ist WLAN bei schwachem Signal bei der Übergabe der Datenverbindung an den Mobilfunk aggressiver."</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 04e1a8c..857420c 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Χρήση ελέγχου HDCP μόνο για περιεχόμενο DRM"</item>
     <item msgid="45075631231212732">"Να χρησιμοποιείται πάντα έλεγχος HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Προεπιλογή"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Προεπιλογή"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Προεπιλογή"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Προεπιλογή"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Προεπιλογή"</item>
-    <item msgid="5618929009984956469">"16 bit/δείγμα"</item>
-    <item msgid="3412640499234627248">"24 bit/δείγμα"</item>
-    <item msgid="121583001492929387">"32 bit/δείγμα"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Προεπιλογή"</item>
-    <item msgid="4726688794884191540">"16 bit/δείγμα"</item>
-    <item msgid="305344756485516870">"24 bit/δείγμα"</item>
-    <item msgid="244568657919675099">"32 bit/δείγμα"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Προεπιλογή"</item>
-    <item msgid="4106832974775067314">"Μονοφωνικό"</item>
-    <item msgid="5571632958424639155">"Στερεοφωνικό"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Προεπιλογή"</item>
-    <item msgid="8900559293912978337">"Μονοφωνικό"</item>
-    <item msgid="8883739882299884241">"Στερεοφωνικό"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Προτιμ. ποιότητα ήχου (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Τυπική (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Προτιμώμενη σύνδεση (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Προτιμ. ποιότητα ήχου (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Τυπική (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Προτιμώμενη σύνδεση (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Ανενεργό"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 8d3df55..67365a3 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Απενεργοποίηση απόλυτης έντασης"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Κωδικοποιητής ήχου Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Επιλέξτε τον προτιμώμενο κωδικοποιητή A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Ρυθμός δειγματοληψίας ήχου Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Επιλέξτε τον προτιμώμενο ρυθμό δειγματοληψίας του κωδικοποιητή A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit ανά δείγμα ήχου Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Επιλέξτε τα προτιμώμενα bit ανά δείγμα για τον κωδικοποιητή A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Λειτουργία καναλιού ήχου Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Επιλέξτε την προτιμώμενη λειτουργία καναλιού κωδικοποιητή A2DP Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Ποιότητα αναπαραγωγής LDAC ήχου Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Επιλέξτε την προτιμώμενη ποιότητα αναπαραγωγής LDAC του κωδικοποιητή A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Εμφάνιση επιλογών για πιστοποίηση ασύρματης οθόνης"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Αύξηση επιπέδου καταγ. Wi-Fi, εμφάνιση ανά SSID RSSI στο εργαλείο επιλογής Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Όταν είναι ενεργό, το Wi-Fi θα μεταβιβάζει πιο επιθετικά τη σύνδ.δεδομένων σε δίκτυο κινητής τηλ., όταν το σήμα Wi-Fi είναι χαμηλό"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 5242be3..4758019 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Use HDCP checking for DRM content only"</item>
     <item msgid="45075631231212732">"Always use HDCP checking"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Default"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Default"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Default"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Default"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Default"</item>
-    <item msgid="5618929009984956469">"16 bits/sample"</item>
-    <item msgid="3412640499234627248">"24 bits/sample"</item>
-    <item msgid="121583001492929387">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Default"</item>
-    <item msgid="4726688794884191540">"16 bits/sample"</item>
-    <item msgid="305344756485516870">"24 bits/sample"</item>
-    <item msgid="244568657919675099">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Default"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Default"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Sound quality preferred (990 Kbps/909 Kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 Kbps/606 Kbps)"</item>
-    <item msgid="4777177307869441982">"Connection preferred (330 Kbps/303 Kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Sound quality preferred (990 Kbps/909 Kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 Kbps/606 Kbps)"</item>
-    <item msgid="3367904477834831032">"Connection preferred (330 Kbps/303 Kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Off"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index f09206d..bb8fc15 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Select Preferred Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Select Preferred Bluetooth A2DP Codec Sample Rate"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Select Preferred Bluetooth A2DP Codec Bits Per Sample"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Select Preferred Bluetooth A2DP Codec Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Audio LDAC Playback Quality"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Select Preferred Bluetooth A2DP Codec LDAC Playback Quality"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 5242be3..4758019 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Use HDCP checking for DRM content only"</item>
     <item msgid="45075631231212732">"Always use HDCP checking"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Default"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Default"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Default"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Default"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Default"</item>
-    <item msgid="5618929009984956469">"16 bits/sample"</item>
-    <item msgid="3412640499234627248">"24 bits/sample"</item>
-    <item msgid="121583001492929387">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Default"</item>
-    <item msgid="4726688794884191540">"16 bits/sample"</item>
-    <item msgid="305344756485516870">"24 bits/sample"</item>
-    <item msgid="244568657919675099">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Default"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Default"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Sound quality preferred (990 Kbps/909 Kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 Kbps/606 Kbps)"</item>
-    <item msgid="4777177307869441982">"Connection preferred (330 Kbps/303 Kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Sound quality preferred (990 Kbps/909 Kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 Kbps/606 Kbps)"</item>
-    <item msgid="3367904477834831032">"Connection preferred (330 Kbps/303 Kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Off"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index f09206d..bb8fc15 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Select Preferred Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Select Preferred Bluetooth A2DP Codec Sample Rate"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Select Preferred Bluetooth A2DP Codec Bits Per Sample"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Select Preferred Bluetooth A2DP Codec Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Audio LDAC Playback Quality"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Select Preferred Bluetooth A2DP Codec LDAC Playback Quality"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 5242be3..4758019 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Use HDCP checking for DRM content only"</item>
     <item msgid="45075631231212732">"Always use HDCP checking"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Default"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Default"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Default"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Default"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Default"</item>
-    <item msgid="5618929009984956469">"16 bits/sample"</item>
-    <item msgid="3412640499234627248">"24 bits/sample"</item>
-    <item msgid="121583001492929387">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Default"</item>
-    <item msgid="4726688794884191540">"16 bits/sample"</item>
-    <item msgid="305344756485516870">"24 bits/sample"</item>
-    <item msgid="244568657919675099">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Default"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Default"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Sound quality preferred (990 Kbps/909 Kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 Kbps/606 Kbps)"</item>
-    <item msgid="4777177307869441982">"Connection preferred (330 Kbps/303 Kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Sound quality preferred (990 Kbps/909 Kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 Kbps/606 Kbps)"</item>
-    <item msgid="3367904477834831032">"Connection preferred (330 Kbps/303 Kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Off"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index f09206d..bb8fc15 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobile data always active"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Select Preferred Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Select Preferred Bluetooth A2DP Codec Sample Rate"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Select Preferred Bluetooth A2DP Codec Bits Per Sample"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Select Preferred Bluetooth A2DP Codec Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Audio LDAC Playback Quality"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Select Preferred Bluetooth A2DP Codec LDAC Playback Quality"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Show options for wireless display certification"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Increase Wi‑Fi logging level, show per SSID RSSI in Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"When enabled, Wi‑Fi will be more aggressive in handing over the data connection to Mobile, when Wi‑Fi signal is low"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index d574edd..4df4952 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Usar comprobación HDCP para contenido DRM solamente"</item>
     <item msgid="45075631231212732">"Siempre utilizar comprobación HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Predeterminado"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Predeterminado"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Predeterminado"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Predeterminado"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Predeterminado"</item>
-    <item msgid="5618929009984956469">"16 bits/muestra"</item>
-    <item msgid="3412640499234627248">"24 bits/muestra"</item>
-    <item msgid="121583001492929387">"32 bits/muestra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Predeterminado"</item>
-    <item msgid="4726688794884191540">"16 bits/muestra"</item>
-    <item msgid="305344756485516870">"24 bits/muestra"</item>
-    <item msgid="244568657919675099">"32 bits/muestra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Predeterminado"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Predeterminado"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Calidad de sonido (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Estándar (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Conexión preferida (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Calidad de sonido (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Estándar (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Conexión preferida (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Desactivado"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index b8b8ce4..9d9a087 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móviles siempre activos"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec del audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecciona el códec A2DP de Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frecuencia de la muestra del audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecciona la frecuencia de la muestra preferida del códec A2DP de Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
+    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frecuencia de muestreo del audio Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por muestra del audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecciona los bits por muestra del códec A2DP de Bluetooth preferidos"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal del audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selecciona el modo de canal del códec A2DP de Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Calidad de reproducción LDAC del audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selecciona la calidad de reproducción LDAC preferida del códec A2DP del audio Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones de certificación de pantalla inalámbrica"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar nivel de registro Wi-Fi; mostrar por SSID RSSI en el selector de Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más intensa al transferir la conexión de datos al celular (si la señal Wi‑Fi es débil)."</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 1cfbe7e..bf492c7 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -58,66 +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>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Predeterminado"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Predeterminado"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Predeterminado"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Predeterminado"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Predeterminado"</item>
-    <item msgid="5618929009984956469">"16 bits por muestra"</item>
-    <item msgid="3412640499234627248">"24 bits por muestra"</item>
-    <item msgid="121583001492929387">"32 bits por muestra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Predeterminado"</item>
-    <item msgid="4726688794884191540">"16 bits por muestra"</item>
-    <item msgid="305344756485516870">"24 bits por muestra"</item>
-    <item msgid="244568657919675099">"32 bits por muestra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Predeterminado"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Predeterminado"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Calidad son. pref. (990 kbps / 909 kbps)"</item>
-    <item msgid="138837449700903545">"Estándar (660 kbps / 606 kbps)"</item>
-    <item msgid="4777177307869441982">"Conexión preferida (330 kbps / 303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Calidad son. pref. (990 kbps / 909 kbps)"</item>
-    <item msgid="9091111147684472529">"Estándar (660 kbps / 606 kbps)"</item>
-    <item msgid="3367904477834831032">"Conexión preferida (330 kbps / 303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <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-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index e4c9ba9..2e4be1c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móviles siempre activos"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecciona el códec A2DP de Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Porcentaje de muestreo de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecciona el porcentaje de muestreo del códec A2DP de Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits de audio por Bluetooth por muestra"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecciona los bits del códec A2DP de Bluetooth preferidos por muestra"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selecciona el modo de canal del códec A2DP de Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Calidad de la reproducción LDAC de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selecciona la calidad de la reproducción LDAC del códec A2DP de Bluetooth preferida"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opciones para la certificación de la pantalla inalámbrica"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar el nivel de logging de Wi-Fi, mostrar por SSID RSSI en el selector Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si está habilitada, la conexión Wi‑Fi será más agresiva al transferir la conexión de datos al móvil (si la señal Wi‑Fi no es estable)"</string>
diff --git a/packages/SettingsLib/res/values-et/arrays.xml b/packages/SettingsLib/res/values-et/arrays.xml
index ba8e8de..ca60dfa 100644
--- a/packages/SettingsLib/res/values-et/arrays.xml
+++ b/packages/SettingsLib/res/values-et/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Kasuta HDCP-kontrolli ainult DRM-sisu korral"</item>
     <item msgid="45075631231212732">"Kasuta alati HDCP-kontrollimist"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Vaikeseade"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Vaikeseade"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Vaikeseade"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Vaikeseade"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Vaikeseade"</item>
-    <item msgid="5618929009984956469">"16 bitti diskreedi kohta"</item>
-    <item msgid="3412640499234627248">"24 bitti diskreedi kohta"</item>
-    <item msgid="121583001492929387">"32 bitti diskreedi kohta"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Vaikeseade"</item>
-    <item msgid="4726688794884191540">"16 bitti diskreedi kohta"</item>
-    <item msgid="305344756485516870">"24 bitti diskreedi kohta"</item>
-    <item msgid="244568657919675099">"32 bitti diskreedi kohta"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Vaikeseade"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Vaikeseade"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Eelist. helikvaliteeti (990/909 kbit/s)"</item>
-    <item msgid="138837449700903545">"Standardne (660/606 kbit/s)"</item>
-    <item msgid="4777177307869441982">"Eelistatakse ühendust (330/303 kbit/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Eelist. helikvaliteeti (990/909 kbit/s)"</item>
-    <item msgid="9091111147684472529">"Standardne (660/606 kbit/s)"</item>
-    <item msgid="3367904477834831032">"Eelistatakse ühendust (330/303 kbit/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Väljas"</item>
     <item msgid="1593289376502312923">"64 000"</item>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index a7b066a..c51e2eb 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiilne andmeside on alati aktiivne"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Keela absoluutne helitugevus"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetoothi heli kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Eelistatud Bluetooth A2DP kodeki valimine"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetoothi heli diskreetimissagedus"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Bluetooth A2DP kodeki eelistatud diskreetimissageduse valimine"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetoothi heli bitte diskreedi kohta"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Bluetooth A2DP kodeki eelistatud bittide arvu valimine diskreedi kohta"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetoothi heli kanalirežiim"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Bluetooth A2DP kodeki eelistatud kanalirežiimi valimine"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetoothi heli LDAC esituskvaliteet"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Bluetooth A2DP kodeki eelistatud LDAC esituskvaliteedi valimine"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Juhtmeta ekraaniühenduse sertifitseerimisvalikute kuvamine"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Suurenda WiFi logimistaset, kuva WiFi valijas SSID RSSI järgi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kui see on lubatud, siis püüab WiFi nõrga WiFi-signaali korral agressiivsemalt anda andmeside ühenduse üle mobiilsele andmesidele"</string>
diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml
index 222aba0..807d562 100644
--- a/packages/SettingsLib/res/values-eu/arrays.xml
+++ b/packages/SettingsLib/res/values-eu/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Erabili HDCP egiaztapena DRM edukirako soilik"</item>
     <item msgid="45075631231212732">"Erabili beti HDCP egiaztapena"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Lehenetsia"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Lehenetsia"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Lehenetsia"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Lehenetsia"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Lehenetsia"</item>
-    <item msgid="5618929009984956469">"16 bit lagin bakoitzeko"</item>
-    <item msgid="3412640499234627248">"24 bit lagin bakoitzeko"</item>
-    <item msgid="121583001492929387">"32 bit lagin bakoitzeko"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Lehenetsia"</item>
-    <item msgid="4726688794884191540">"16 bit lagin bakoitzeko"</item>
-    <item msgid="305344756485516870">"24 bit lagin bakoitzeko"</item>
-    <item msgid="244568657919675099">"32 bit lagin bakoitzeko"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Lehenetsia"</item>
-    <item msgid="4106832974775067314">"Monoa"</item>
-    <item msgid="5571632958424639155">"Estereoa"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Lehenetsia"</item>
-    <item msgid="8900559293912978337">"Monoa"</item>
-    <item msgid="8883739882299884241">"Estereoa"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Soinu-kalitate hobetsia (990 kb/s edo 909 kb/s)"</item>
-    <item msgid="138837449700903545">"Arrunta (660 kb/s edo 606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Konexio hobetsia (330 kb/s edo 303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Soinu-kalitate hobetsia (990 kb/s edo 909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Arrunta (660 kb/s edo 606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Konexio hobetsia (330 kb/s edo 303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Desaktibatuta"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 514d136..98177d2f 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mugikorreko datuak beti aktibo"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desgaitu bolumen absolutua"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth bidezko audioaren kodeka"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Hautatu Bluetooth A2DP kodek hobetsia"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth bidezko audioaren lagin-abiadura"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Hautatu Bluetooth A2DP kodekaren lagin-abiadura hobetsia"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth bidezko audioaren lagin bakoitzeko bit kopurua"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Hautatu Bluetooth A2DP kodekaren lagin bakoitzeko bit kopuru hobetsia"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth bidezko audioaren kanalaren modua"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Hautatu Bluetooth A2DP kodekaren kanalaren modu hobetsia"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth bidezko audioaren LDAC erreprodukzioaren kalitatea"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Hautatu Bluetooth A2DP kodekaren LDAC erreprodukzioaren kalitate hobetsia"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Erakutsi hari gabeko bistaratze-egiaztapenaren aukerak"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Erakutsi datu gehiago Wi-Fi sareetan saioa hasterakoan. Erakutsi sarearen identifikatzailea eta seinalearen indarra Wi‑Fi sareen hautagailuan."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Aukera hori gaituz gero, gailua errazago aldatuko da datu mugikorren konexiora Wi-Fi seinalea ahultzen dela nabaritutakoan"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 1ff0d25..293639c 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"‏استفاده از بررسی HDCP فقط برای محتوای DRM"</item>
     <item msgid="45075631231212732">"‏همیشه از بررسی HDCP استفاده شود"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"پیش‌فرض"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"پیش‌فرض"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"پیش‌فرض"</item>
-    <item msgid="8895532488906185219">"۴۴٫۱ کیلوهرتز"</item>
-    <item msgid="2909915718994807056">"۴۸٫۰ کیلوهرتز"</item>
-    <item msgid="3347287377354164611">"۸۸٫۲ کیلوهرتز"</item>
-    <item msgid="1234212100239985373">"۹۶٫۰ کیلوهرتز"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"پیش‌فرض"</item>
-    <item msgid="4482862757811638365">"۴۴٫۱ کیلوهرتز"</item>
-    <item msgid="354495328188724404">"۴۸٫۰ کیلوهرتز"</item>
-    <item msgid="7329816882213695083">"۸۸٫۲ کیلوهرتز"</item>
-    <item msgid="6967397666254430476">"۹۶٫۰ کیلوهرتز"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"پیش‌فرض"</item>
-    <item msgid="5618929009984956469">"۱۶ بیت در هر نمونه"</item>
-    <item msgid="3412640499234627248">"۲۴ بیت در هر نمونه"</item>
-    <item msgid="121583001492929387">"۳۲ بیت در هر نمونه"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"پیش‌فرض"</item>
-    <item msgid="4726688794884191540">"۱۶ بیت در هر نمونه"</item>
-    <item msgid="305344756485516870">"۲۴ بیت در هر نمونه"</item>
-    <item msgid="244568657919675099">"۳۲ بیت در هر نمونه"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"پیش‌فرض"</item>
-    <item msgid="4106832974775067314">"مونو"</item>
-    <item msgid="5571632958424639155">"استریو"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"پیش‌فرض"</item>
-    <item msgid="8900559293912978337">"مونو"</item>
-    <item msgid="8883739882299884241">"استریو"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"کیفیت صدای ترجیحی (۹۹۰کیلوبیت در ثانیه/۹۰۹کیلوبیت در ثانیه)"</item>
-    <item msgid="138837449700903545">"استاندارد (۶۶۰کیلوبیت در ثانیه/۶۰۶کیلوبیت در ثانیه)"</item>
-    <item msgid="4777177307869441982">"اتصال ترجیحی (۳۳۰کیلوبیت در ثانیه/۳۰۳کیلوبیت در ثانیه)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"کیفیت صدای ترجیحی (۹۹۰کیلوبیت در ثانیه/۹۰۹کیلوبیت در ثانیه)"</item>
-    <item msgid="9091111147684472529">"استاندارد (۶۶۰کیلوبیت در ثانیه/۶۰۶کیلوبیت در ثانیه)"</item>
-    <item msgid="3367904477834831032">"اتصال ترجیحی (۳۳۰کیلوبیت در ثانیه/۳۰۳کیلوبیت در ثانیه)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"خاموش"</item>
     <item msgid="1593289376502312923">"۶۴ هزار"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index d6518e1..9f0b639 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"داده سلولی همیشه فعال"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"غیرفعال کردن میزان صدای مطلق"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"کدک بلوتوث صوتی"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"‏انتخاب کدک‌ A2DP در بلوتوث ترجیحی"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"سرعت نمونه بلوتوث صوتی"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"‏انتخاب سرعت نمونه کدک‌ A2DP بلوتوث ترجیحی"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"بیت‌های بلوتوث صوتی در هر نمونه"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"‏انتخاب بیت‌های کدک‌ A2DP بلوتوث ترجیحی هر نمونه"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"حالت کانال بلوتوث‌ صوتی"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"‏انتخاب حالت کانال کدک‌ A2DP بلوتوث ترجیحی"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"‏کیفیت پخش LDAC بلوتوث صوتی"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"‏انتخاب کیفیت پخش LDAC کدک‌ A2DP بلوتوث ترجیحی"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"نمایش گزینه‌ها برای گواهینامه نمایش بی‌سیم"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏افزایش سطح گزارش‌گیری Wi‑Fi، نمایش به ازای SSID RSSI در انتخاب‌کننده Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏وقتی فعال است، در شرایط پایین بودن سیگنال، Wi‑Fi برای واگذار کردن اتصال داده به شبکه سلولی فعال‌تر خواهد بود."</string>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 5d842a4..2808bf2 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Käytä HDCP-tarkistusta vain DRM-suojatulle sisällölle"</item>
     <item msgid="45075631231212732">"Käytä aina HDCP-tarkistusta"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Oletus"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Oletus"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Oletus"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Oletus"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Oletus"</item>
-    <item msgid="5618929009984956469">"16 bittiä/näyte"</item>
-    <item msgid="3412640499234627248">"24 bittiä/näyte"</item>
-    <item msgid="121583001492929387">"32 bittiä/näyte"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Oletus"</item>
-    <item msgid="4726688794884191540">"16 bittiä/näyte"</item>
-    <item msgid="305344756485516870">"24 bittiä/näyte"</item>
-    <item msgid="244568657919675099">"32 bittiä/näyte"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Oletus"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Oletus"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Äänenlaatu etusijalla (990 kbps / 909 kbps)"</item>
-    <item msgid="138837449700903545">"Vakio (660 kbps / 606 kbps)"</item>
-    <item msgid="4777177307869441982">"Yhteys etusijalla (330 kbps / 303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Äänenlaatu etusijalla (990 kbps / 909 kbps)"</item>
-    <item msgid="9091111147684472529">"Vakio (660 kbps / 606 kbps)"</item>
-    <item msgid="3367904477834831032">"Yhteys etusijalla (330 kbps / 303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Ei käytössä"</item>
     <item msgid="1593289376502312923">"64 kt"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 2332fc5..7f78001 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiilidata on aina käytössä"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-äänen koodekki"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Valitse ensisijainen Bluetooth A2DP ‑koodekki"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth-ääninäytteen siirtonopeus"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Valitse ensisijainen Bluetooth A2DP ‑koodekkinäytteen siirtonopeus"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth-äänen bittiä/näyte-arvo"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Valitse ensisijainen Bluetooth A2DP ‑koodekin bittiä/näyte-arvo"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth-äänen kanavatila"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Valitse ensisijainen Bluetooth A2DP ‑koodekin kanavatila"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth-äänen LDAC-toiston laatu"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Valitse ensisijainen Bluetooth A2DP ‑koodekin LDAC-toiston laatu"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Näytä langattoman näytön sertifiointiin liittyvät asetukset"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Lisää Wi‑Fin lokikirjaustasoa, näytä SSID RSSI -kohtaisesti Wi‑Fi-valitsimessa."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kun asetus on käytössä, Wi-Fi siirtää datayhteyden aggressiivisemmin matkapuhelinverkolle, jos Wi-Fi-signaali on heikko."</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index c50e576..7c403bf 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Utiliser la vérification HDCP uniquement pour le contenu GDN"</item>
     <item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Par défaut"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Par défaut"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Par défaut"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Par défaut"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Par défaut"</item>
-    <item msgid="5618929009984956469">"16 bits par échantillon"</item>
-    <item msgid="3412640499234627248">"24 bits par échantillon"</item>
-    <item msgid="121583001492929387">"32 bits par échantillon"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Par défaut"</item>
-    <item msgid="4726688794884191540">"16 bits par échantillon"</item>
-    <item msgid="305344756485516870">"24 bits par échantillon"</item>
-    <item msgid="244568657919675099">"32 bits par échantillon"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Par défaut"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stéréo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Par défaut"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stéréo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qualité sonore préférée (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Connexion préférée (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qualité sonore préférée (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Connexion préférée (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Désactivé"</item>
     <item msgid="1593289376502312923">"64 ko"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 9eeeccb7c..cd0ab25 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Données cellulaires toujours actives"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Sélectionnez le codec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taux d\'échantillonnage pour l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Sélectionnez le taux d\'échantillonnage préféré pour le codec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits par échantillon pour l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Sélectionnez le nombre de bits par échantillon préféré pour le codec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode de canal pour l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Sélectionnez le mode de canal préféré pour le codec Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualité de lecture LDAC pour l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Sélectionnez la qualité de lecture LDAC préférée pour le codec Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options pour la certification d\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si cette option est activée, le passage du Wi-Fi aux données cellulaires est forcé lorsque le signal Wi-Fi est faible"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index cda881c..c63275f 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Utiliser la vérification HDCP uniquement pour le contenu DRM"</item>
     <item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Par défaut"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Par défaut"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Par défaut"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Par défaut"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Par défaut"</item>
-    <item msgid="5618929009984956469">"16 bits par échantillon"</item>
-    <item msgid="3412640499234627248">"24 bits par échantillon"</item>
-    <item msgid="121583001492929387">"32 bits par échantillon"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Par défaut"</item>
-    <item msgid="4726688794884191540">"16 bits par échantillon"</item>
-    <item msgid="305344756485516870">"24 bits par échantillon"</item>
-    <item msgid="244568657919675099">"32 bits par échantillon"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Par défaut"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stéréo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Par défaut"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stéréo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qualité audio prioritaire (990/909 kbit/s)"</item>
-    <item msgid="138837449700903545">"Standard (660/606 kbit/s)"</item>
-    <item msgid="4777177307869441982">"Connexion prioritaire (330/303 kbits/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qualité audio prioritaire (990/909 kbit/s)"</item>
-    <item msgid="9091111147684472529">"Standard (660/606 kbit/s)"</item>
-    <item msgid="3367904477834831032">"Connexion prioritaire (330/303 kbits/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Désactivé"</item>
     <item msgid="1593289376502312923">"64 Ko"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 8ba0b0f..8587e28 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Données mobiles toujours actives"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Sélectionner le codec A2DP Bluetooth prioritaire"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taux d\'échantillonnage audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Sélectionner le taux d\'échantillonnage pour le codec A2DP Bluetooth prioritaire"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Nombre de bits par échantillon pour l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Sélectionner le nombre de bits par échantillon pour le codec A2DP Bluetooth prioritaire"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode de chaîne de l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Sélectionner le mode de chaîne pour le codec A2DP Bluetooth prioritaire"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualité de lecture LDAC de l\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Sélectionner la qualité de lecture LDAC pour le codec A2DP Bluetooth prioritaire"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afficher les options de la certification de l\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Détailler plus infos Wi-Fi, afficher par RSSI de SSID dans outil sélection Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Si cette option est activée, le passage du Wi-Fi aux données mobiles est forcé en cas de signal Wi-Fi faible."</string>
diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml
index e581368..2a89199 100644
--- a/packages/SettingsLib/res/values-gl/arrays.xml
+++ b/packages/SettingsLib/res/values-gl/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Utiliza a comprobación HDCP só para contido DRM"</item>
     <item msgid="45075631231212732">"Utilizar sempre a comprobación HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Predeterminado"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Predeterminado"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Predeterminado"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Predeterminado"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Predeterminado"</item>
-    <item msgid="5618929009984956469">"16 bits/mostra"</item>
-    <item msgid="3412640499234627248">"24 bits/mostra"</item>
-    <item msgid="121583001492929387">"32 bits/mostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Predeterminado"</item>
-    <item msgid="4726688794884191540">"16 bits/mostra"</item>
-    <item msgid="305344756485516870">"24 bits/mostra"</item>
-    <item msgid="244568657919675099">"32 bits/mostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Predeterminado"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Predeterminado"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Calidade preferida (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Estándar (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Conexión preferida (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Calidade preferida (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Estándar (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Conexión preferida (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Desactivado"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 6a9a1ec..6820575 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Datos móbiles sempre activados"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactivar volume absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Seleccionar códec A2DP de Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de mostraxe de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Seleccionar taxa de mostraxe do códec A2DP de Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por mostra de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Seleccionar bits por mostra do códec A2DP de Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canle de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Seleccionar modo de canle do códec A2DP de Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Calidade de reprodución de LDAC de audio por Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Seleccionar calidade de reprodución de LDAC do códec A2DP de Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opcións para o certificado de visualización sen fíos"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nivel de rexistro da wifi, mostrar por SSID RSSI no selector de wifi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Cando está activada esta función, a wifi será máis agresiva ao entregar a conexión de datos ao móbil, cando o sinal wifi é feble"</string>
diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml
index 742103b..d41cfbc 100644
--- a/packages/SettingsLib/res/values-gu/arrays.xml
+++ b/packages/SettingsLib/res/values-gu/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"ફક્ત DRM સામગ્રી માટે HDCP તપાસનો ઉપયોગ કરો"</item>
     <item msgid="45075631231212732">"હંમેશા HDCP તપાસનો ઉપયોગ કરો"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ડિફૉલ્ટ"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ડિફૉલ્ટ"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ડિફૉલ્ટ"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ડિફૉલ્ટ"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ડિફૉલ્ટ"</item>
-    <item msgid="5618929009984956469">"16 બિટ/નમૂનો"</item>
-    <item msgid="3412640499234627248">"24 બિટ/નમૂનો"</item>
-    <item msgid="121583001492929387">"32 બિટ/નમૂનો"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ડિફૉલ્ટ"</item>
-    <item msgid="4726688794884191540">"16 બિટ/નમૂનો"</item>
-    <item msgid="305344756485516870">"24 બિટ/નમૂનો"</item>
-    <item msgid="244568657919675099">"32 બિટ/નમૂનો"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ડિફૉલ્ટ"</item>
-    <item msgid="4106832974775067314">"મૉનો"</item>
-    <item msgid="5571632958424639155">"સ્ટીરિઓ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ડિફૉલ્ટ"</item>
-    <item msgid="8900559293912978337">"મૉનો"</item>
-    <item msgid="8883739882299884241">"સ્ટીરિઓ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"પસંદગીની અવાજ ગુણવત્તા (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"માનક (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"પસંદગીનું કનેક્શન (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"પસંદગીની અવાજ ગુણવત્તા (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"માનક (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"પસંદગીનું કનેક્શન (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"બંધ"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index e61e6e2..8e68ab0 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"સેલ્યુલર ડેટા હંમેશા સક્રિય"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth ઑડિઓ કોડેક"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"પસંદગીના Bluetooth A2DP કોડેકને પસંદ કરો"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth ઑડિઓ નમૂના દર"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"પસંદગીના Bluetooth A2DP કોડેક નમૂના દરને પસંદ કરો"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"નમૂના દીઠ Bluetooth ઑડિઓ બિટ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"નમૂના દીઠ પસંદગીના Bluetooth A2DP કોડેક બિટને પસંદ કરો"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth ઑડિઓ ચેનલ મોડ"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"પસંદગીના Bluetooth A2DP કોડેક ચેનલ મોડને પસંદ કરો"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth ઑડિઓ LDAC પ્લેબેક ગુણવત્તા"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"પસંદગીની Bluetooth A2DP કોડેક LDAC પ્લેબેક ગુણવત્તા પસંદ કરો"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"વાયરલેસ ડિસ્પ્લે પ્રમાણપત્ર માટેના વિકલ્પો બતાવો"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi લોગિંગ સ્તર વધારો, Wi‑Fi પીકરમાં SSID RSSI દીઠ બતાવો"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"જ્યારે સક્ષમ હોય, ત્યારે Wi‑Fi સિગ્નલ ઓછા હોવા પર, સેલ્યુલર પર ડેટા કનેક્શન મોકલવામાં વધુ આક્રમક હશે"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 11b83c9..489e8e7 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP जांच का उपयोग केवल DRM सामग्री के लिए करें"</item>
     <item msgid="45075631231212732">"हमेशा HDCP जांच का उपयोग करें"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"डिफ़ॉल्ट"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"डिफ़ॉल्ट"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"डिफ़ॉल्ट"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"डिफ़ॉल्ट"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"डिफ़ॉल्ट"</item>
-    <item msgid="5618929009984956469">"16 बिट/नमूना"</item>
-    <item msgid="3412640499234627248">"24 बिट/नमूना"</item>
-    <item msgid="121583001492929387">"32 बिट/नमूना"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"डिफ़ॉल्ट"</item>
-    <item msgid="4726688794884191540">"16 बिट/नमूना"</item>
-    <item msgid="305344756485516870">"24 बिट/नमूना"</item>
-    <item msgid="244568657919675099">"32 बिट/नमूना"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"डिफ़ॉल्ट"</item>
-    <item msgid="4106832974775067314">"मोनो"</item>
-    <item msgid="5571632958424639155">"स्टीरियो"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"डिफ़ॉल्ट"</item>
-    <item msgid="8900559293912978337">"मोनो"</item>
-    <item msgid="8883739882299884241">"स्टीरियो"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"पसंदीदा ध्वनि गुणवत्ता (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"मानक (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"पसंदीदा कनेक्शन (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"पसंदीदा ध्वनि गुणवत्ता (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"मानक (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"पसंदीदा कनेक्शन (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"बंद"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 7ba3d54..fd01c6b 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा हमेशा सक्रिय"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"पूर्ण वॉल्यूम अक्षम करें"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लूटूथ ऑडियो कोडेक"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"पसंदीदा ब्लूटूथ A2DP कोडेक चुनें"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ब्लूटूथ ऑडियो नमूना दर"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"पसंदीदा ब्लूटूथ A2DP कोडेक नमूना दर चुनें"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ब्लूटूथ ऑडियो बिट प्रति नमूना"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"पसंदीदा ब्लूटूथ A2DP कोडेक बिट प्रति नमूना चुनें"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ब्लूटूथ ऑडियो चैनल मोड"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"पसंदीदा ब्लूटूथ A2DP कोडेक चैनल मोड चुनें"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ब्लूटूथ ऑडियो LDAC प्लेबैक गुणवत्ता"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"पसंदीदा ब्लूटूथ A2DP कोडेक LDAC प्लेबैक गुणवत्ता चुनें"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस दिखाई देने के लिए प्रमाणन विकल्प दिखाएं"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाई-फ़ाई प्रवेश स्तर बढ़ाएं, वाई-फ़ाई पिकर में प्रति SSID RSSI दिखाएं"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"इसके सक्षम होने पर, जब वाई-फ़ाई संकेत कमज़ोर हों तो वाई-फ़ाई, डेटा कनेक्शन को सेल्यूलर पर अधिक बलपूर्वक भेजेगा"</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 114337a..8415bee 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Upotrebljavaj HDCP provjeru samo za DRM sadržaj"</item>
     <item msgid="45075631231212732">"Uvijek upotrebljavaj HDCP provjeru"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Zadano"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Zadano"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Zadano"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Zadano"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Zadano"</item>
-    <item msgid="5618929009984956469">"16 bitova po uzorku"</item>
-    <item msgid="3412640499234627248">"24 bita po uzorku"</item>
-    <item msgid="121583001492929387">"32 bita po uzorku"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Zadano"</item>
-    <item msgid="4726688794884191540">"16 bitova po uzorku"</item>
-    <item msgid="305344756485516870">"24 bita po uzorku"</item>
-    <item msgid="244568657919675099">"32 bita po uzorku"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Zadano"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Zadano"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Željena kval. zvuka (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standardna (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Željeno povezivanje (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Željena kval. zvuka (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standardna (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Željeno povezivanje (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Isključeno"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 598e5cb..21fdce5 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući apsolutnu glasnoću"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek za Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Odabir željenog Bluetooth A2DP kodeka"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorka za Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Odabir željenu brzinu uzorka Bluetooth A2DP kodeka"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bitovi po uzorku za Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Odabir željenog broja bitova po uzorku za Bluetooth A2DP kodek"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način kanala za Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Odabir željenog načina kanala Bluetooth A2DP kodeka"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"LDAC kvaliteta reprodukcije za Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Odabir željene kvalitete reprodukcije Bluetooth A2DP kodeka LDAC"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaži opcije za certifikaciju bežičnog prikaza"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećana razina prijave na Wi‑Fi, prikaz po SSID RSSI-ju u Biraču Wi‑Fi-ja"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ako je omogućeno, Wi-Fi će aktivno prebacivati podatkovnu vezu mobilnoj mreži kada je Wi-Fi signal slab."</string>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 4cc67a3..9f314ac 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Csak DRM-tartalomhoz használjon HDCP ellenőrzést"</item>
     <item msgid="45075631231212732">"Mindig használjon HDCP ellenőrzést"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Alapértelmezett"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Alapértelmezett"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Alapértelmezett"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Alapértelmezett"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Alapértelmezett"</item>
-    <item msgid="5618929009984956469">"16 bit/minta"</item>
-    <item msgid="3412640499234627248">"24 bit/minta"</item>
-    <item msgid="121583001492929387">"32 bit/minta"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Alapértelmezett"</item>
-    <item msgid="4726688794884191540">"16 bit/minta"</item>
-    <item msgid="305344756485516870">"24 bit/minta"</item>
-    <item msgid="244568657919675099">"32 bit/minta"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Alapértelmezett"</item>
-    <item msgid="4106832974775067314">"Monó"</item>
-    <item msgid="5571632958424639155">"Sztereó"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Alapértelmezett"</item>
-    <item msgid="8900559293912978337">"Monó"</item>
-    <item msgid="8883739882299884241">"Sztereó"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Minőség előnyben részesítése (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Alapértelmezett (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Kapcsolat előnyben részesítése (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Minőség előnyben részesítése (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Alapértelmezett (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Kapcsolat előnyben részesítése (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Ki"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index f4be3ec..63c38d0 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"A mobilhálózati adatforgalom mindig aktív"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Abszolút hangerő funkció letiltása"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth hang – Kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Előnyben részesített kodek kiválasztása a Bluetooth A2DP profiljához"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth hang – mintavételezési gyakoriság"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Kodek előnyben részesített mintavételezési gyakoriságának kiválasztása a Bluetooth A2DP profiljához"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth hang – bit/minta"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Kodek előnyben részesített bit/minta mennyiségének kiválasztása a Bluetooth A2DP profiljához"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth hang – Csatornamód"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Kodek előnyben részesített csatornamódjának kiválasztása a Bluetooth A2DP profiljához"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth hang – LDAC lejátszási minőség"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Kodek előnyben részesített LDAC lejátszási minőségének kiválasztása a Bluetooth A2DP profiljához"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vezeték nélküli kijelző tanúsítványával kapcsolatos lehetőségek megjelenítése"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-naplózási szint növelése, RSSI/SSID megjelenítése a Wi‑Fi-választóban"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ha engedélyezi, a Wi-Fi agresszívebben fogja átadni az adatkapcsolatot a mobilhálózatnak gyenge Wi-Fi-jel esetén"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index ab810bf..057399e 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Օգտագործել HDCP-ը` միայն DRM-ի բովանդակությունը ստուգելու համար"</item>
     <item msgid="45075631231212732">"Միշտ օգտագործել HDCP ստուգումը"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Կանխադրված"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Կանխադրված"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Կանխադրված"</item>
-    <item msgid="8895532488906185219">"44,1 կՀց"</item>
-    <item msgid="2909915718994807056">"48,0 կՀց"</item>
-    <item msgid="3347287377354164611">"88,2 կՀց"</item>
-    <item msgid="1234212100239985373">"96,0 կՀց"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Կանխադրված"</item>
-    <item msgid="4482862757811638365">"44,1 կՀց"</item>
-    <item msgid="354495328188724404">"48,0 կՀց"</item>
-    <item msgid="7329816882213695083">"88,2 կՀց"</item>
-    <item msgid="6967397666254430476">"96,0 կՀց"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Կանխադրված"</item>
-    <item msgid="5618929009984956469">"16 բիթ/նմուշ"</item>
-    <item msgid="3412640499234627248">"24 բիթ/նմուշ"</item>
-    <item msgid="121583001492929387">"32 բիթ/նմուշ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Կանխադրված"</item>
-    <item msgid="4726688794884191540">"16 բիթ/նմուշ"</item>
-    <item msgid="305344756485516870">"24 բիթ/նմուշ"</item>
-    <item msgid="244568657919675099">"32 բիթ/նմուշ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Կանխադրված"</item>
-    <item msgid="4106832974775067314">"Մոնո"</item>
-    <item msgid="5571632958424639155">"Ստերեո"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Կանխադրված"</item>
-    <item msgid="8900559293912978337">"Մոնո"</item>
-    <item msgid="8883739882299884241">"Ստերեո"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Նախընտրելի է ձայնի որակը (990 կբ/վ / 909 կբ/վ)"</item>
-    <item msgid="138837449700903545">"Ստանդարտ (660 կբ/վ / 606 կբ/վ)"</item>
-    <item msgid="4777177307869441982">"Նախընտրելի է կապը (330 կբ/վ / 303 կբ/վ)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Նախընտրելի է ձայնի որակը (990 կբ/վ / 909 կբ/վ)"</item>
-    <item msgid="9091111147684472529">"Ստանդարտ (660 կբ/վ / 606 կբ/վ)"</item>
-    <item msgid="3367904477834831032">"Նախընտրելի է կապը (330 կբ/վ / 303 կբ/վ)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Անջատված է"</item>
     <item msgid="1593289376502312923">"64ԿԲ"</item>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 5ee1570..b4efac1 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Բջջային տվյալները՝ միշտ ակտիվացրած"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth աուդիո կոդեկ"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Ընտրեք Bluetooth A2DP նախընտրելի կոդեկը"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth աուդիոյի Ընդհատավորման հաճախականությունը"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Ընտրեք Bluetooth A2DP կոդեկի Ընդհատավորման նախընտրելի հաճախականությունը"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth աուդիո, բիթ / նմուշ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Ընտրեք Bluetooth A2DP կոդեկի նախընտրելի որակը, բիթ / նմուշ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth աուդիո կապուղու ռեժիմը"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Ընտրեք Bluetooth A2DP կոդեկի կապուղու նախընտրելի ռեժիմը"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth աուդիո LDAC նվագարկման որակը"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Ընտրեք Bluetooth A2DP կոդեկի LDAC նվագարկման նախընտրելի որակը"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ցույց տալ անլար էկրանի հավաստագրման ընտրանքները"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Բարձրացնել մակարդակը, Wi‑Fi ընտրիչում ամեն մի SSID-ի համար ցույց տալ RSSI"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Եթե այս գործառույթը միացված է, Wi‑Fi-ի թույլ ազդանշանի դեպքում Wi‑Fi ինտերնետից անցումը բջջային ինտերնետին ավելի կտրուկ կլինի"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index be3d89c..1ccf993 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Gunakan pemeriksaan HDCP untuk konten DRM saja"</item>
     <item msgid="45075631231212732">"Selalu gunakan pemeriksaan HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Default"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Default"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Default"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Default"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Default"</item>
-    <item msgid="5618929009984956469">"16 bit/sampel"</item>
-    <item msgid="3412640499234627248">"24 bit/sampel"</item>
-    <item msgid="121583001492929387">"32 bit/sampel"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Default"</item>
-    <item msgid="4726688794884191540">"16 bit/sampel"</item>
-    <item msgid="305344756485516870">"24 bit/sampel"</item>
-    <item msgid="244568657919675099">"32 bit/sampel"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Default"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Default"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Kualitas suara yang disukai (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standar (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Sambungan yang disukai (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Kualitas suara yang disukai (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standar (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Sambungan yang disukai (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Nonaktif"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 97eca8e..a2f13ae 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Data seluler selalu aktif"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Nonaktifkan volume absolut"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Pilih Codec A2DP Bluetooth Yang Disukai"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frekuensi Sampel Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Pilih Frekuensi Sampel Codec A2DP Bluetooth Yang Disukai"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit Per Sampel Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Pilih Bit Per Sampel Codec A2DP Bluetooth Yang Disukai"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mode Channel Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Pilih Mode Channel Codec A2DP Bluetooth Yang Disukai"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Kualitas Pemutaran LDAC Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Pilih Kualitas Pemutaran LDAC Codec A2DP Bluetooth Yang Disukai"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tampilkan opsi untuk sertifikasi layar nirkabel"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan level pencatatan log Wi-Fi, tampilkan per SSID RSSI di Pemilih Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Jika diaktifkan, Wi-Fi akan menjadi lebih agresif dalam mengalihkan sambungan data ke Seluler saat sinyal Wi-Fi lemah"</string>
diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml
index dbb1636..94ce957 100644
--- a/packages/SettingsLib/res/values-is/arrays.xml
+++ b/packages/SettingsLib/res/values-is/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Nota HDCP-athugun aðeins fyrir höfundarréttarvarið efni"</item>
     <item msgid="45075631231212732">"Nota alltaf HDCP-eftirlit"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Sjálfgefið"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Sjálfgefið"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Sjálfgefið"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Sjálfgefið"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Sjálfgefið"</item>
-    <item msgid="5618929009984956469">"16 bitar/úrtak"</item>
-    <item msgid="3412640499234627248">"24 bitar/úrtak"</item>
-    <item msgid="121583001492929387">"32 bitar/úrtak"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Sjálfgefið"</item>
-    <item msgid="4726688794884191540">"16 bitar/úrtak"</item>
-    <item msgid="305344756485516870">"24 bitar/úrtak"</item>
-    <item msgid="244568657919675099">"32 bitar/úrtak"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Sjálfgefið"</item>
-    <item msgid="4106832974775067314">"Einóma"</item>
-    <item msgid="5571632958424639155">"Víðóma"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Sjálfgefið"</item>
-    <item msgid="8900559293912978337">"Einóma"</item>
-    <item msgid="8883739882299884241">"Víðóma"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Hljóðgæði í forgangi (990kb/s / 909kb/s)"</item>
-    <item msgid="138837449700903545">"Venjulegt (660kb/s / 606kb/s)"</item>
-    <item msgid="4777177307869441982">"Tenging í forgangi (330kb/s / 303kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Hljóðgæði í forgangi (990kb/s / 909kb/s)"</item>
-    <item msgid="9091111147684472529">"Venjulegt (660kb/s / 606kb/s)"</item>
-    <item msgid="3367904477834831032">"Tenging í forgangi (330kb/s / 303kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Slökkt"</item>
     <item msgid="1593289376502312923">"64 k"</item>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 4cecdbc..f50f97e 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Alltaf kveikt á farsímagögnum"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slökkva á samstillingu hljóðstyrks"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth hljóðkóðari"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Veldu Bluetooth A2DP kóðara"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth hljóðtökutíðni"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Veldu Bluetooth A2DP kóðaratökutíðni"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth hljóðbitar í úrtaki"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Veldu Bluetooth A2DP kóðarabita í úrtaki"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hljóðrásarstilling Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Veldu Bluetooth A2DP stillingu kóðararásar"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth LDAC gæði hljóðspilunar"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Veldu Bluetooth LDAC spilunargæði A2DP kóðara"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Sýna valkosti fyrir vottun þráðlausra skjáa"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Auka skráningarstig Wi-Fi, sýna RSSI fyrir hvert SSID í Wi-Fi vali"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Þegar þetta er virkt mun Wi-Fi ganga harðar fram í að færa gagnatenginguna yfir til símkerfisins þegar Wi-Fi merkið er lélegt"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 5349086..d5ca891c 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Usa la verifica HDCP solo per contenuti DRM"</item>
     <item msgid="45075631231212732">"Usa sempre la verifica HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Valore predefinito"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Valore predefinito"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Valore predefinito"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Valore predefinito"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Valore predefinito"</item>
-    <item msgid="5618929009984956469">"16 bit/campione"</item>
-    <item msgid="3412640499234627248">"24 bit/campione"</item>
-    <item msgid="121583001492929387">"32 bit/campione"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Valore predefinito"</item>
-    <item msgid="4726688794884191540">"16 bit/campione"</item>
-    <item msgid="305344756485516870">"24 bit/campione"</item>
-    <item msgid="244568657919675099">"32 bit/campione"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Valore predefinito"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Valore predefinito"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qualità audio preferita (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Collegamento preferito (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qualità audio preferita (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Collegamento preferito (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Off"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index a33fa87..14f41fa 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dati cellulare sempre attivi"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disattiva volume assoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Seleziona codec A2DP Bluetooth preferito"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frequenza di campionamento audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Seleziona frequenza di campionamento preferita codec A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit per campione dell\'audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Seleziona bit per campione preferiti codec A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modalità canale audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Seleziona modalità canale preferita codec A2DP Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualità di riproduzione LDAC audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Seleziona qualità di riproduzione preferita LDAC codec A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostra opzioni per la certificazione display wireless"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumenta il livello di registrazione Wi-Fi, mostrando il SSID RSSI nel selettore Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando questa impostazione è attivata, il Wi-Fi sarà più aggressivo nel passare la connessione dati al cellulare, quando il segnale Wi-Fi è basso"</string>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 621e14d..94af5f1 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"‏השתמש בבדיקת HDCP עבור תוכן DRM בלבד"</item>
     <item msgid="45075631231212732">"‏תמיד השתמש בבדיקת HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ברירת מחדל"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ברירת מחדל"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ברירת מחדל"</item>
-    <item msgid="8895532488906185219">"44.1 קילו-הרץ"</item>
-    <item msgid="2909915718994807056">"48.0 קילו-הרץ"</item>
-    <item msgid="3347287377354164611">"88.2 קילו-הרץ"</item>
-    <item msgid="1234212100239985373">"96.0 קילו-הרץ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ברירת מחדל"</item>
-    <item msgid="4482862757811638365">"44.1 קילו-הרץ"</item>
-    <item msgid="354495328188724404">"48.0 קילו-הרץ"</item>
-    <item msgid="7329816882213695083">"88.2 קילו-הרץ"</item>
-    <item msgid="6967397666254430476">"96.0 קילו-הרץ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ברירת מחדל"</item>
-    <item msgid="5618929009984956469">"16 סיביות/דגימה"</item>
-    <item msgid="3412640499234627248">"24 סיביות/דגימה"</item>
-    <item msgid="121583001492929387">"32 סיביות/דגימה"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ברירת מחדל"</item>
-    <item msgid="4726688794884191540">"16 סיביות/דגימה"</item>
-    <item msgid="305344756485516870">"24 סיביות/דגימה"</item>
-    <item msgid="244568657919675099">"32 סיביות/דגימה"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ברירת מחדל"</item>
-    <item msgid="4106832974775067314">"מונו"</item>
-    <item msgid="5571632958424639155">"סטריאו"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ברירת מחדל"</item>
-    <item msgid="8900559293912978337">"מונו"</item>
-    <item msgid="8883739882299884241">"סטריאו"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"‏איכות צליל מועדפת (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"‏רגילה (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"‏חיבור מועדף (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"‏איכות צליל מועדפת (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"‏רגילה (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"‏חיבור מועדף (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"כבוי"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 45dd7e7..5b26091 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"נתונים סלולריים פעילים תמיד"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"השבת עוצמת קול מוחלטת"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"‏Codec אודיו ל-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"‏בחר codec ‏A2DP מועדף ל-Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"‏קצב דגימה של אודיו ל-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"‏בחר קצב דגימה מועדף ב-codec ‏‏A2DP ל-Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"‏מספר סיביות לדגימה באודיו ל-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"‏בחר מספר מועדף של סיביות לדגימה ב-codec ‏‏A2DP ל-Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"‏מצב של ערוץ אודיו ל-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"‏בחר מצב ערוץ מועדף ב-codec ‏‏A2DP ל-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"‏איכות נגינה של אודיו LDAC ל-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"‏בחר איכות נגינה מועדפת ב-codec ‏‏A2DP ל-Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"‏הצג אפשרויות עבור אישור של תצוגת WiFi"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏העלה את רמת הרישום של Wi‑Fi ביומן, הצג לכל SSID RSSI ב-Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏כשתכונה זו מופעלת, Wi-Fi יתנהג בצורה אגרסיבית יותר בעת העברת חיבור הנתונים לרשת הסלולרית כשאות ה-Wi-Fi חלש."</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index cc00934..c8599d2 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRMコンテンツにのみHDCPチェックを使用する"</item>
     <item msgid="45075631231212732">"HDCPチェックを常に使用する"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"デフォルト"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"デフォルト"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"デフォルト"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"デフォルト"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"デフォルト"</item>
-    <item msgid="5618929009984956469">"16 ビット / サンプル"</item>
-    <item msgid="3412640499234627248">"24 ビット / サンプル"</item>
-    <item msgid="121583001492929387">"32 ビット / サンプル"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"デフォルト"</item>
-    <item msgid="4726688794884191540">"16 ビット / サンプル"</item>
-    <item msgid="305344756485516870">"24 ビット / サンプル"</item>
-    <item msgid="244568657919675099">"32 ビット / サンプル"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"デフォルト"</item>
-    <item msgid="4106832974775067314">"モノラル"</item>
-    <item msgid="5571632958424639155">"ステレオ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"デフォルト"</item>
-    <item msgid="8900559293912978337">"モノラル"</item>
-    <item msgid="8883739882299884241">"ステレオ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"優先する音質(990 kbps / 909 kbps)"</item>
-    <item msgid="138837449700903545">"標準(660 kbps / 606 kbps)"</item>
-    <item msgid="4777177307869441982">"優先する接続(330 kbps / 303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"優先する音質(990 kbps / 909 kbps)"</item>
-    <item msgid="9091111147684472529">"標準(660 kbps / 606 kbps)"</item>
-    <item msgid="3367904477834831032">"優先する接続(330 kbps / 303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"OFF"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 12a8734..72f4595 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"モバイルデータを常にON"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"絶対音量を無効にする"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth オーディオ コーデック"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"優先する Bluetooth A2DP コーデックを選択"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth オーディオ サンプルレート"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"優先する Bluetooth A2DP コーデック サンプルレートを選択"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"サンプルあたりの Bluetooth オーディオ ビット"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"優先するサンプルあたりの Bluetooth A2DP コーデック ビットを選択"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth オーディオ チャンネル モード"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"優先する Bluetooth A2DP コーデック チャンネル モードを選択"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth オーディオ LDAC 再生音質"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"優先する Bluetooth A2DP コーデック LDAC 再生音質を選択"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ワイヤレスディスプレイ認証のオプションを表示"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fiログレベルを上げて、Wi-Fi選択ツールでSSID RSSIごとに表示します"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"有効にすると、Wi-Fiの電波強度が弱い場合は強制的にモバイルデータ接続に切り替わるようになります"</string>
diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml
index 0e6eb7c..60779fe 100644
--- a/packages/SettingsLib/res/values-ka/arrays.xml
+++ b/packages/SettingsLib/res/values-ka/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP შემოწმების გამოყენება მხოლოდ DRM კონტენტის შემთხვევაში"</item>
     <item msgid="45075631231212732">"ყოველთვის გამოიყენე HDCP შემოწმება"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ნაგულისხმევი"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ნაგულისხმევი"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ნაგულისხმევი"</item>
-    <item msgid="8895532488906185219">"44,1 კჰც"</item>
-    <item msgid="2909915718994807056">"48,0 კჰც"</item>
-    <item msgid="3347287377354164611">"88,2 კჰც"</item>
-    <item msgid="1234212100239985373">"96,0 კჰც"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ნაგულისხმევი"</item>
-    <item msgid="4482862757811638365">"44,1 კჰც"</item>
-    <item msgid="354495328188724404">"48,0 კჰც"</item>
-    <item msgid="7329816882213695083">"88,2 კჰც"</item>
-    <item msgid="6967397666254430476">"96,0 კჰც"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ნაგულისხმევი"</item>
-    <item msgid="5618929009984956469">"16 ბიტი/ნიმუში"</item>
-    <item msgid="3412640499234627248">"24 ბიტი/ნიმუში"</item>
-    <item msgid="121583001492929387">"32 ბიტი/ნიმუში"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ნაგულისხმევი"</item>
-    <item msgid="4726688794884191540">"16 ბიტი/ნიმუში"</item>
-    <item msgid="305344756485516870">"24 ბიტი/ნიმუში"</item>
-    <item msgid="244568657919675099">"32 ბიტი/ნიმუში"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ნაგულისხმევი"</item>
-    <item msgid="4106832974775067314">"მონო"</item>
-    <item msgid="5571632958424639155">"სტერეო"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ნაგულისხმევი"</item>
-    <item msgid="8900559293912978337">"მონო"</item>
-    <item msgid="8883739882299884241">"სტერეო"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"სასურველია ხმის ხარისხი (990/909 კბიტი/წმ)"</item>
-    <item msgid="138837449700903545">"სტანდარტული (660/606 კბიტი/წმ)"</item>
-    <item msgid="4777177307869441982">"სასურველია კავშირი (330/303 კბიტი/წმ)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"სასურველია ხმის ხარისხი (990/909 კბიტი/წმ)"</item>
-    <item msgid="9091111147684472529">"სტანდარტული (660/606 კბიტი/წმ)"</item>
-    <item msgid="3367904477834831032">"სასურველია კავშირი (330/303 კბიტი/წმ)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"გამორთული"</item>
     <item msgid="1593289376502312923">"64 კბაიტი"</item>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 18c2def..058562e 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ფიჭური მონაცემები ყოველთვის აქტიურია"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth აუდიოს კოდეკი"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"აირჩიეთ Bluetooth A2DP-ის სასურველი კოდეკი"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth აუდიოს დისკრეტიზაციის სიხშირე"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"აირჩიეთ Bluetooth A2DP კოდეკის დისკრეტიზაციის სასურველი სიხშირე"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth აუდიოს ბიტების რაოდენობა ნიმუშზე"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"აირჩიეთ Bluetooth A2DP კოდეკის ბიტების სასურველი რაოდენობა ნიმუშზე"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth აუდიოს არხის რეჟიმი"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"აირჩიეთ Bluetooth A2DP კოდეკის არხის სასურველი რეჟიმი"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth აუდიოს LDAC დაკვრის ხარისხი"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"აირჩიეთ Bluetooth A2DP კოდეკის LDAC დაკვრის სასურველი ხარისხი"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"უსადენო ეკრანის სერტიფიცირების ვარიანტების ჩვენება"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi-ს აღრიცხვის დონის გაზრდა, Wi‑Fi ამომრჩეველში ყოველ SSID RSSI-ზე ჩვენება"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"თუ ჩართულია, Wi‑Fi სიგნალის შესუსტების შემთხვევაში Wi-Fi უფრო აქტიურად შეეცდება გადაიყვანოს ინტერნეტ-კავშირი მობილურ ინტერნეტზე"</string>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index e253a79..f743606 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP (кең жолақты сандық мазмұн қорғау) тексеруді DRM (авторлық құқықты техникалық қорғау) мазмұны үшін ғана қолданыңыз"</item>
     <item msgid="45075631231212732">"Әрқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Әдепкі"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Әдепкі"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Әдепкі"</item>
-    <item msgid="8895532488906185219">"44,1 кГц"</item>
-    <item msgid="2909915718994807056">"48,0 кГц"</item>
-    <item msgid="3347287377354164611">"88,2 кГц"</item>
-    <item msgid="1234212100239985373">"96,0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Әдепкі"</item>
-    <item msgid="4482862757811638365">"44,1 кГц"</item>
-    <item msgid="354495328188724404">"48,0 кГц"</item>
-    <item msgid="7329816882213695083">"88,2 кГц"</item>
-    <item msgid="6967397666254430476">"96,0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Әдепкі"</item>
-    <item msgid="5618929009984956469">"16 бит/үлгі"</item>
-    <item msgid="3412640499234627248">"24 бит/үлгі"</item>
-    <item msgid="121583001492929387">"32 бит/үлгі"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Әдепкі"</item>
-    <item msgid="4726688794884191540">"16 бит/үлгі"</item>
-    <item msgid="305344756485516870">"24 бит/үлгі"</item>
-    <item msgid="244568657919675099">"32 бит/үлгі"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Әдепкі"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Әдепкі"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Таңдаулы дыбыс сапасы (990 кб/сек не 909 кб/сек)"</item>
-    <item msgid="138837449700903545">"Стандартты (660 кб/сек не 606 кб/сек)"</item>
-    <item msgid="4777177307869441982">"Таңдаулы байланыс (330 кб/сек не 303 кб/сек)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Таңдаулы дыбыс сапасы (990 кб/сек не 909 кб/сек)"</item>
-    <item msgid="9091111147684472529">"Стандартты (660 кб/сек не 606 кб/сек)"</item>
-    <item msgid="3367904477834831032">"Таңдаулы байланыс (330 кб/сек не 303 кб/сек)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Өшірулі"</item>
     <item msgid="1593289376502312923">"64 КБ"</item>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 505b118..69610fa 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -170,16 +170,24 @@
     <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi роумингін іздеулерге әрқашан рұқсат ету"</string>
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Ұялы деректер әрқашан белсенді"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string>
-    <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұны кодегі"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Таңдаулы Bluetooth A2DP кодегін таңдау"</string>
+    <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұн кодегі"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудиомазмұны бойынша үлгі жиілігі"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Таңдаулы Bluetooth A2DP кодегі бойынша үлгі жиілігі"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth аудиомазмұны бойынша әр үлгіге келетін биттер саны"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Таңдаулы Bluetooth A2DP кодегі бойынша әр үлгіге келетін биттер санын таңдау"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудиомазмұны бойынша арна режимі"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Таңдаулы Bluetooth A2DP кодегі бойынша арна режимі"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth аудиомазмұны бойынша LDAC ойнату сапасы"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Таңдаулы Bluetooth A2DP кодегі бойынша LDAC ойнату сапасын таңдау"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Сымсыз дисплей растау опцияларын көрсету"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi жур. тір. дең. арт., Wi‑Fi желісін таңдағышта әр SSID RSSI бойынша көрсету"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wi‑Fi сигналы әлсіз болғанда, деректер байланысы мәжбүрлі түрде ұялы желіге ауысады"</string>
diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml
index 569603f..470112a 100644
--- a/packages/SettingsLib/res/values-km/arrays.xml
+++ b/packages/SettingsLib/res/values-km/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"ប្រើ​ការ​ពិនិត្យ HDCP សម្រាប់​តែ​មាតិកា DRM ប៉ុណ្ណោះ"</item>
     <item msgid="45075631231212732">"ប្រើ​ការ​ពិនិត្យ HDCP ជា​និច្ច"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"លំ​នាំ​ដើម"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"លំ​នាំ​ដើម"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"លំនាំដើម"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"លំ​នាំ​ដើម"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"លំ​នាំ​ដើម"</item>
-    <item msgid="5618929009984956469">"16 ប៊ីត​/​គំរូ"</item>
-    <item msgid="3412640499234627248">"24 ប៊ីត​/​គំរូ"</item>
-    <item msgid="121583001492929387">"32 ប៊ីត​/​គំរូ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"លំ​នាំ​ដើម"</item>
-    <item msgid="4726688794884191540">"16 ប៊ីត​/​គំរូ"</item>
-    <item msgid="305344756485516870">"24 ប៊ីត​/​គំរូ"</item>
-    <item msgid="244568657919675099">"32 ប៊ីត​/​គំរូ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"លំ​នាំ​ដើម"</item>
-    <item msgid="4106832974775067314">"ម៉ូ​ណូ"</item>
-    <item msgid="5571632958424639155">"ស្តេរ៉េអូ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"លំ​នាំ​ដើម"</item>
-    <item msgid="8900559293912978337">"ម៉ូ​ណូ"</item>
-    <item msgid="8883739882299884241">"ស្តេរ៉េអូ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"គុណភាព​សំឡេង​ដែល​គួរ​ប្រើ (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"ស្តង់ដា (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"ការ​ត​ភ្ជាប់​ដែល​គួរ​ប្រើ (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"គុណភាព​សំឡេង​ដែល​គួរ​ប្រើ (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"ស្តង់ដា (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"ការ​ត​ភ្ជាប់​ដែល​គួរ​ប្រើ (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"បិទ"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index b7bddd8..205f01b 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ទិន្នន័យចល័តសកម្មជានិច្ច"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"កូឌិក​សំឡេង​ប៊្លូធូស"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ជ្រើស​រើស​កូឌិក​សម្រាប់​ប៊្លូធូស A2DP ដែល​គួរ​ប្រើ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"អត្រា​គំរូ​សំឡេង​ប៊្លូធូស"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ជ្រើសរើស​អត្រា​គំរូ​កូឌិក​សម្រាប់​ប៊្លូធូស A2DP ដែល​គួរ​ប្រើ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"កម្រិត​ប៊ីត​ក្នុង​មួយ​គំរូ​នៃ​សំឡេង​ប៊្លូធូស"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ជ្រើសរើស​កម្រិត​ប៊ីត​ក្នុង​មួយ​គំរូ​នៃ​កូឌិក​ប៊្លូធូស A2DP ដែល​គួរ​ប្រើ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"មុខ​ងារ​រលកសញ្ញា​សំឡេង​ប៊្លូធូស"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ជ្រើស​រើស​មុខងារ​រលក​សញ្ញា​កូឌិក​ប៊្លូធូស A2DP ដែល​គួរ​ប្រើ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"គុណភាព​ចាក់​សម្រាប់​សំឡេង​ប៊្លូធូស LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"ជ្រើសរើស​គុណភាព​ចាក់ LDAC កូឌិក សម្រាប់​ប៊្លូធូស A2DP ដែល​គួរ​ប្រើ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"បង្ហាញ​ជម្រើស​សម្រាប់​វិញ្ញាបនបត្រ​បង្ហាញ​ឥត​ខ្សែ"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"បង្កើនកម្រិតកំណត់ហេតុវ៉ាយហ្វាយបង្ហាញក្នុង SSID RSSI ក្នុងកម្មវិធីជ្រើស​វ៉ាយហ្វាយ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ពេល​បាន​បើក វ៉ាយហ្វាយ​នឹង​កាន់តែ​បង្ខំ​ក្នុង​ការ​បញ្ជូន​ការ​ភ្ជាប់​ទិន្នន័យ​ទៅ​បណ្ដាញ​ចល័ត នៅ​ពេល​សញ្ញា​វ៉ាយហ្វាយ​យឺត"</string>
diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml
index ae3e97d..d26f95a 100644
--- a/packages/SettingsLib/res/values-kn/arrays.xml
+++ b/packages/SettingsLib/res/values-kn/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM ವಿಷಯಗಳಿಗೆ ಮಾತ್ರ HDCP ಪರೀಕ್ಷಿಸುವಿಕೆಯನ್ನು ಬಳಸು"</item>
     <item msgid="45075631231212732">"HDCP ಪರಿಶೀಲನೆಯನ್ನು ಯಾವಾಗಲೂ ಬಳಸು"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="5618929009984956469">"16 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
-    <item msgid="3412640499234627248">"24 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
-    <item msgid="121583001492929387">"32 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="4726688794884191540">"16 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
-    <item msgid="305344756485516870">"24 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
-    <item msgid="244568657919675099">"32 ಬಿಟ್ಸ್/ಮಾದರಿ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="4106832974775067314">"ಮೊನೊ"</item>
-    <item msgid="5571632958424639155">"ಸ್ಟೀರಿಯೊ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ಡಿಫಾಲ್ಟ್"</item>
-    <item msgid="8900559293912978337">"ಮೊನೊ"</item>
-    <item msgid="8883739882299884241">"ಸ್ಟೀರಿಯೊ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"ಧ್ವನಿಯ ಗುಣಮಟ್ಟಕ್ಕೆ ಆದ್ಯತೆ ನೀಡಲಾಗಿದೆ (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"ಪ್ರಮಾಣಿತ (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"ಸಂಪರ್ಕಕ್ಕೆ ಆದ್ಯತೆ ನೀಡಲಾಗಿದೆ (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"ಧ್ವನಿಯ ಗುಣಮಟ್ಟಕ್ಕೆ ಆದ್ಯತೆ ನೀಡಲಾಗಿದೆ (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"ಪ್ರಮಾಣಿತ (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"ಸಂಪರ್ಕಕ್ಕೆ ಆದ್ಯತೆ ನೀಡಲಾಗಿದೆ (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ಆಫ್"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 5ac99d3..e43883e 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ಸೆಲ್ಯುಲರ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಕೋಡೆಕ್"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ಪ್ರಾಶಸ್ತ್ಯದ ಬ್ಲೂಟೂತ್ A2DP ಕೋಡೆಕ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಮಾದರಿ ದರ"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ಪ್ರಾಶಸ್ತ್ಯದ ಬ್ಲೂಟೂಥ್ A2DP ಕೋಡೆಕ್ ಮಾದರಿ ದರವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ ಬಿಟ್ಸ್‌‌ನ ಪ್ರತಿ ಮಾದರಿ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ಪ್ರಾಶಸ್ತ್ಯದ ಬ್ಲೂಟೂತ್‌ A2DP ಕೋಡೆಕ್ ಬಿಟ್ಸ್‌ನ ಪ್ರತಿ ಮಾದರಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಚಾನೆಲ್ ಮೋಡ್"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ಪ್ರಾಶಸ್ತ್ಯದ ಬ್ಲೂಟೂತ್‌ A2DP ಕೋಡೆಕ್ ಚಾನಲ್ ಮೋಡ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ಬ್ಲೂಟೂತ್‌ ಆಡಿಯೊ LDAC ಪ್ಲೇಬ್ಯಾಕ್ ಗುಣಮಟ್ಟ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"ಪ್ರಾಶಸ್ತ್ಯದ ಬ್ಲೂಟೂತ್‌ A2DP ಕೋಡೆಕ್ LDAC ಪ್ಲೇಬ್ಯಾಕ್ ಗುಣಮಟ್ಟವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ವೈರ್‌ಲೆಸ್‌‌‌ ಪ್ರದರ್ಶನ ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಆಯ್ಕೆಗಳನ್ನು ತೋರಿಸು"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ಲಾಗಿಂಗ್ ಮಟ್ಟನ್ನು ಹೆಚ್ಚಿಸಿ, Wi‑Fi ಆಯ್ಕೆಯಲ್ಲಿ ಪ್ರತಿಯೊಂದು SSID RSSI ತೋರಿಸಿ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ಸಕ್ರಿಯಗೊಂಡರೆ, Wi‑Fi ಸಿಗ್ನಲ್ ದುರ್ಬಲವಾಗಿದ್ದರೂ ಕೂಡ, ಸೆಲ್ಯುಲರ್‌ಗೆ ಡೇಟಾ ಸಂಪರ್ಕವನ್ನು ಹಸ್ತಾಂತರಿಸುವಲ್ಲಿ Wi‑Fi ಹೆಚ್ಚು ಆಕ್ರಮಣಕಾರಿಯಾಗಿರುತ್ತದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index f709e88..3c8424a 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM 콘텐츠에 대해서만 HDCP 확인 사용"</item>
     <item msgid="45075631231212732">"항상 HDCP 확인 사용"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"기본값"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"기본값"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"기본값"</item>
-    <item msgid="8895532488906185219">"44.1kHz"</item>
-    <item msgid="2909915718994807056">"48.0kHz"</item>
-    <item msgid="3347287377354164611">"88.2kHz"</item>
-    <item msgid="1234212100239985373">"96.0kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"기본값"</item>
-    <item msgid="4482862757811638365">"44.1kHz"</item>
-    <item msgid="354495328188724404">"48.0kHz"</item>
-    <item msgid="7329816882213695083">"88.2kHz"</item>
-    <item msgid="6967397666254430476">"96.0kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"기본값"</item>
-    <item msgid="5618929009984956469">"16비트/샘플"</item>
-    <item msgid="3412640499234627248">"24비트/샘플"</item>
-    <item msgid="121583001492929387">"32비트/샘플"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"기본값"</item>
-    <item msgid="4726688794884191540">"16비트/샘플"</item>
-    <item msgid="305344756485516870">"24비트/샘플"</item>
-    <item msgid="244568657919675099">"32비트/샘플"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"기본값"</item>
-    <item msgid="4106832974775067314">"모노"</item>
-    <item msgid="5571632958424639155">"스테레오"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"기본값"</item>
-    <item msgid="8900559293912978337">"모노"</item>
-    <item msgid="8883739882299884241">"스테레오"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"음질 우선(990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"표준(660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"연결 우선(330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"음질 우선(990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"표준(660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"연결 우선(330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"사용 안함"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index a21fb25..0a8c727 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"모바일 데이터 항상 활성화"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"절대 볼륨 사용 안함"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"블루투스 오디오 코덱"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"기본 블루투스 A2DP 코덱 선택"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"블루투스 오디오 샘플링 비율"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"기본 블루투스 A2DP 코덱 샘플링 비율 선택"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"블루투스 오디오 샘플당 비트"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"기본 블루투스 A2DP 코덱 샘플당 비트 선택"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"블루투스 오디오 채널 모드"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"기본 블루투스 A2DP 코덱 채널 모드 선택"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"블루투스 오디오 LDAC 재생 품질"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"기본 블루투스 A2DP 코덱 LDAC 재생 품질 선택"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"무선 디스플레이 인증서 옵션 표시"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi 로깅 수준을 높이고, Wi‑Fi 선택도구에서 SSID RSSI당 값을 표시합니다."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"사용 설정하면 Wi-Fi 신호가 약할 때 데이터 연결을 Wi-Fi에서 데이터 네트워크로 더욱 적극적으로 핸드오버합니다."</string>
diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml
index 84d9002..724d0c7 100644
--- a/packages/SettingsLib/res/values-ky/arrays.xml
+++ b/packages/SettingsLib/res/values-ky/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP текшерүү DRM мазмунуна гана колдонулсун"</item>
     <item msgid="45075631231212732">"Ар дайым HDCP текшерүү колдонулсун"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Демейки"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Демейки"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Демейки"</item>
-    <item msgid="8895532488906185219">"44,1 кГц"</item>
-    <item msgid="2909915718994807056">"48,0 кГц"</item>
-    <item msgid="3347287377354164611">"88,2 кГц"</item>
-    <item msgid="1234212100239985373">"96,0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Демейки"</item>
-    <item msgid="4482862757811638365">"44,1 кГц"</item>
-    <item msgid="354495328188724404">"48,0 кГц"</item>
-    <item msgid="7329816882213695083">"88,2 кГц"</item>
-    <item msgid="6967397666254430476">"96,0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Демейки"</item>
-    <item msgid="5618929009984956469">"16 бит/үлгү"</item>
-    <item msgid="3412640499234627248">"24 бит/үлгү"</item>
-    <item msgid="121583001492929387">"32 бит/үлгү"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Демейки"</item>
-    <item msgid="4726688794884191540">"16 бит/үлгү"</item>
-    <item msgid="305344756485516870">"24 бит/үлгү"</item>
-    <item msgid="244568657919675099">"32 бит/үлгү"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Демейки"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Демейки"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Тандалган добуш сапаты (990Кб/сек./909Кб/сек.)"</item>
-    <item msgid="138837449700903545">"Стандарт (660Кб/сек./606Кб/сек.)"</item>
-    <item msgid="4777177307869441982">"Тандалган туташуу (330Кб/сек./303Кб/сек.)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Тандалган добуш сапаты (990Кб/сек./909Кб/сек.)"</item>
-    <item msgid="9091111147684472529">"Стандарт (660Кб/сек./606Кб/сек.)"</item>
-    <item msgid="3367904477834831032">"Тандалган туташуу (330Кб/сек./303Кб/сек.)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Өчүк"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index d1320da..1a8aee3 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Уюлдук дайындар ар дайым активдүү"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодек"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Керектүү Bluetooth A2DP кодекти тандаңыз"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудио үлгүсүнүн ылдамдыгы"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Bluetooth A2DP кодек үлгүсүнүн керектүү ылдамдыгын тандаңыз"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Бир үлгүдөгү Bluetooth аудио биттери"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Бир үлгү үчүн керектүү Bluetooth A2DP кодек биттерин тандаңыз"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудио каналынын режими"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Bluetooth A2DP кодек каналынын керектүү режимин тандаңыз"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth аудио LDAC ойнотуу сапаты"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Bluetooth A2DP кодек үчүн керектүү LDAC ойнотуу сапатын тандаңыз"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Зымсыз дисплейди сертификатто мүмкүнчүлүктөрүн көргөзүү"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi Кармагычта Wi‑Fi протокол деңгээлин жогорулатуу жана ар бир SSID RSSI үчүн көрсөтүү."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Иштетилгенде, Wi-Fi байланышы үзүл-кесил болуп жатканда, Wi-Fi дайындарды уюктук операторго өжөрлүк менен өткөрөт."</string>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index 45bb579..4b14eeb 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"ໃຊ້ການກວດສອບ HDCP ສຳລັບເນື້ອຫາ DRM ເທົ່ານັ້ນ"</item>
     <item msgid="45075631231212732">"ໃຊ້ການກວດສອບ HDCP ສະເໝີ"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="5618929009984956469">"16 bits/sample"</item>
-    <item msgid="3412640499234627248">"24 bits/sample"</item>
-    <item msgid="121583001492929387">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="4726688794884191540">"16 bits/sample"</item>
-    <item msgid="305344756485516870">"24 bits/sample"</item>
-    <item msgid="244568657919675099">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="4106832974775067314">"ໂທນດຽວ"</item>
-    <item msgid="5571632958424639155">"ສະເຕຣິໂອ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ຄ່າເລີ່ມຕົ້ນ"</item>
-    <item msgid="8900559293912978337">"ໂທນດຽວ"</item>
-    <item msgid="8883739882299884241">"ສະເຕຣິໂອ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Sound quality preferred (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Connection preferred (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Sound quality preferred (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Connection preferred (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ປິດ"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 639769a..569c0ce 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ຂໍ້​ມູນ​ມື​ຖື​ເປີດ​ຢູ່​ສະ​ເໝີ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Select Preferred Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio Sample Rate"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Select Preferred Bluetooth A2DP Codec Sample Rate"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio Bits Per Sample"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Select Preferred Bluetooth A2DP Codec Bits Per Sample"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Select Preferred Bluetooth A2DP Codec Channel Mode"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Audio LDAC Playback Quality"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Select Preferred Bluetooth A2DP Codec LDAC Playback Quality"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ສະແດງໂຕເລືອກສຳລັບການສະແດງການຮັບຮອງລະບົບໄຮ້ສາຍ"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"ເພີ່ມ​ລະ​ດັບ​ການ​ເກັບ​ປະ​ຫວັດ Wi‑Fi, ສະ​ແດງ​ຕໍ່ SSID RSSI ​ໃນ​ Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ເມື່ອ​ເປີດ​ນຳ​ໃຊ້​ແລ້ວ, ເຄືອ​ຂ່າຍ Wi-Fi ຈະ​ຖືກ​ປ່ຽນ​ໄປ​ໃຊ້​ເຄືອ​ຂ່າຍ​ໂທ​ລະ​ສັບ​ແທນ​ຫາກ​ສັນ​ຍານ Wi-Fi ອ່ອນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index b61b6d8..deed74f 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Taikyti HDCP tikrinimą tik DRM turiniui"</item>
     <item msgid="45075631231212732">"Visada naudoti HDCP tikrinimą"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Numatytasis"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Numatytasis"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Numatytasis"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Numatytasis"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Numatytasis"</item>
-    <item msgid="5618929009984956469">"16 bitų pavyzdyje"</item>
-    <item msgid="3412640499234627248">"24 bitai pavyzdyje"</item>
-    <item msgid="121583001492929387">"32 bitai pavyzdyje"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Numatytasis"</item>
-    <item msgid="4726688794884191540">"16 bitų pavyzdyje"</item>
-    <item msgid="305344756485516870">"24 bitai pavyzdyje"</item>
-    <item msgid="244568657919675099">"32 bitai pavyzdyje"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Numatytasis"</item>
-    <item msgid="4106832974775067314">"Monofoninis garsas"</item>
-    <item msgid="5571632958424639155">"Stereofoninis garsas"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Numatytasis"</item>
-    <item msgid="8900559293912978337">"Monofoninis garsas"</item>
-    <item msgid="8883739882299884241">"Stereofoninis garsas"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Pageid. garso kok. (990 KB/s / 909 KB/s)"</item>
-    <item msgid="138837449700903545">"Įprasta (660 KB/s / 606 KB/s)"</item>
-    <item msgid="4777177307869441982">"Pageidautin. ryšys (330 KB/s / 303 KB/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Pageid. garso kok. (990 KB/s / 909 KB/s)"</item>
-    <item msgid="9091111147684472529">"Įprasta (660 KB/s / 606 KB/s)"</item>
-    <item msgid="3367904477834831032">"Pageidautin. ryšys (330 KB/s / 303 KB/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Išjungta"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 4616b86..28329cc 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Korinio ryšio duomenys visada aktyvūs"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Išjungti didžiausią garsą"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"„Bluetooth“ garso kodekas"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Pasirinkite pageidaujamą „Bluetooth“ A2DP kodeką"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"„Bluetooth“ garso pavyzdžio dažnis"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Pasirinkite pageidaujamą „Bluetooth“ A2DP kodeko pavyzdžio dažnį"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"„Bluetooth“ garso įrašo bitų skaičius pavyzdyje"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Pasirinkite pageidaujamą „Bluetooth“ A2DP kodeko bitų skaičių pavyzdyje"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"„Bluetooth“ garso kanalo režimas"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Pasirinkite pageidaujamą „Bluetooth“ A2DP kodeko kanalo režimą"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"„Bluetooth“ garso LDAC atkūrimo kokybė"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Pasirinkite pageidaujamą „Bluetooth“ A2DP kodeko LDAC atkūrimo kokybę"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rodyti belaidžio rodymo sertifikavimo parinktis"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Padidinti „Wi‑Fi“ įrašymo į žurnalą lygį, rodyti SSID RSSI „Wi-Fi“ rinkiklyje"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Jei įgalinta ši parinktis, „Wi‑Fi“ agresyviau perduos duomenų ryšį į mobiliojo ryšio tinklą, kai „Wi‑Fi“ signalas bus silpnas"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index 1d8a501..cf8b2c9 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Izmantot HDCP pārbaudi tikai DRM saturam"</item>
     <item msgid="45075631231212732">"Vienmēr izmantot HDCP pārbaudi"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Noklusējums"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Noklusējums"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Noklusējums"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Noklusējums"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Noklusējums"</item>
-    <item msgid="5618929009984956469">"16 biti iztvērumā"</item>
-    <item msgid="3412640499234627248">"24 biti iztvērumā"</item>
-    <item msgid="121583001492929387">"32 biti iztvērumā"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Noklusējums"</item>
-    <item msgid="4726688794884191540">"16 biti iztvērumā"</item>
-    <item msgid="305344756485516870">"24 biti iztvērumā"</item>
-    <item msgid="244568657919675099">"32 biti iztvērumā"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Noklusējums"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Noklusējums"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Vēlamā skaņas kvalitāte (990/909 Kb/s)"</item>
-    <item msgid="138837449700903545">"Standarta (660/606 Kb/s)"</item>
-    <item msgid="4777177307869441982">"Vēlamais savienojums (330/303 Kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Vēlamā skaņas kvalitāte (990/909 Kb/s)"</item>
-    <item msgid="9091111147684472529">"Standarta (660/606 Kb/s)"</item>
-    <item msgid="3367904477834831032">"Vēlamais savienojums (330/303 Kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Izslēgts"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index dd17509..b64216a 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Vienmēr aktīvs mobilo datu savienojums"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Atspējot absolūto skaļumu"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodeks"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Atlasīt vēlamo Bluetooth A2DP kodeku"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth audio iztveršanas ātrums"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Atlasīt vēlamo Bluetooth A2DP kodeka iztveršanas ātrumu"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio bitu skaits iztvērumā"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Atlasīt vēlamo Bluetooth A2DP kodeka bitu skaitu iztvērumā"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth audio kanāla režīms"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Atlasīt vēlamo Bluetooth A2DP kodeka kanāla režīmu"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth audio LDAC atskaņošanas kvalitāte"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Atlasīt vēlamo Bluetooth A2DP kodeka LDAC atskaņošanas kvalitāti"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Rādīt bezvadu attēlošanas sertifikācijas iespējas"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Palieliniet Wi‑Fi reģistrēšanas līmeni; rādīt katram SSID RSSI Wi‑Fi atlasītājā."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ja opcija ir iespējota un Wi‑Fi signāls ir vājš, datu savienojuma pāreja no Wi-Fi uz mobilo tīklu tiks veikta agresīvāk."</string>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index e7a9563..72124f7 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Користи ХДЦП проверка само за ДРМ содржина"</item>
     <item msgid="45075631231212732">"Секогаш користи ХДЦП проверка"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Стандардно"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Стандардно"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Стандардно"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Стандардно"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Стандардно"</item>
-    <item msgid="5618929009984956469">"16 бита/примерок"</item>
-    <item msgid="3412640499234627248">"24 бита/примерок"</item>
-    <item msgid="121583001492929387">"32 бита/примерок"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Стандардно"</item>
-    <item msgid="4726688794884191540">"16 бита/примерок"</item>
-    <item msgid="305344756485516870">"24 бита/примерок"</item>
-    <item msgid="244568657919675099">"32 бита/примерок"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Стандардно"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Стандардно"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Прет. квалитет на звук (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Стандардно (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Претпочитана врска (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Прет. квалитет на звук (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Стандардно (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Претпочитана врска (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Исклучено"</item>
     <item msgid="1593289376502312923">"64.000"</item>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index eb0760b..df106ed 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Мобилниот интернет е секогаш активен"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Оневозможете апсолутна јачина на звук"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек за аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Изберете претпочитан кодек за A2DP преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Стапка на примерок аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Изберете претпочитана стапка на примерок за кодек за A2DP преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Бита по примерок аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Изберете претпочитани бита по примерок кодек за A2DP преку Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
+    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Стапка на семпл преку Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Аудио бит-по-семпл преку Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим на канал за аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Изберете претпочитан режим на канал за кодек за A2DP преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Квалитет на репродукција LDAC на аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Изберете претпочитан квалитет на репродукција LDAC на кодек за A2DP преку Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Кога е вклучено, Wi-Fi ќе биде поагресивно при предавање на поврзувањето со податоци на мобилната мрежа при слаб сигнал на Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-ml/arrays.xml b/packages/SettingsLib/res/values-ml/arrays.xml
index 57755ed..38ba63a 100644
--- a/packages/SettingsLib/res/values-ml/arrays.xml
+++ b/packages/SettingsLib/res/values-ml/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM ഉള്ളടക്കത്തിനുമാത്രമായി HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
     <item msgid="45075631231212732">"എല്ലായ്‌പ്പോഴും HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ഡിഫോൾട്ട്"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ഡിഫോൾട്ട്"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ഡിഫോൾട്ട്"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ഡിഫോൾട്ട്"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ഡിഫോൾട്ട്"</item>
-    <item msgid="5618929009984956469">"16 ബിറ്റ്/സാമ്പിൾ"</item>
-    <item msgid="3412640499234627248">"24 ബിറ്റ്/സാമ്പിൾ"</item>
-    <item msgid="121583001492929387">"32 ബിറ്റ്/സാമ്പിൾ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ഡിഫോൾട്ട്"</item>
-    <item msgid="4726688794884191540">"16 ബിറ്റ്/സാമ്പിൾ"</item>
-    <item msgid="305344756485516870">"16 ബിറ്റ്/സാമ്പിൾ"</item>
-    <item msgid="244568657919675099">"32 ബിറ്റ്/സാമ്പിൾ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ഡിഫോൾട്ട്"</item>
-    <item msgid="4106832974775067314">"മോണോ"</item>
-    <item msgid="5571632958424639155">"സ്റ്റീരിയോ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ഡിഫോൾട്ട്"</item>
-    <item msgid="8900559293912978337">"മോണോ"</item>
-    <item msgid="8883739882299884241">"സ്റ്റീരിയോ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"നിർദ്ദേശിക്കുന്ന ശബ്ദ നിലവാരം (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"അടിസ്ഥാനം (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"നിർദ്ദേശിക്കുന്ന കണക്ഷൻ (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"നിർദ്ദേശിക്കുന്ന ശബ്ദ നിലവാരം (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"അടിസ്ഥാനം (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"നിർദ്ദേശിക്കുന്ന കണക്ഷൻ (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ഓഫ്"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index b88298d..f61b71d 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"സെല്ലുലാർ ഡാറ്റ എല്ലായ്‌പ്പോഴും സജീവം"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth ഓഡിയോ കോഡെക്"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"നിർദ്ദേശിക്കുന്ന Bluetooth A2DP കോഡെക് തിരഞ്ഞെടുക്കുക"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth ഓഡിയോ സാമ്പിൾ നിരക്ക്"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"നിർദ്ദേശിക്കുന്ന Bluetooth A2DP കോഡെക് സാമ്പിൾ നിരക്ക് തിരഞ്ഞെടുക്കുക"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"പ്രതി സാമ്പിളിലെ Bluetooth ഓഡിയോ ബിറ്റ് നി"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"പ്രതി സാമ്പിളിന് നിർദ്ദേശിക്കുന്ന Bluetooth A2DP കോഡെക് ബിറ്റ് നിരക്ക് തിരഞ്ഞെടുക്കുക"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth ഓഡിയോ ചാനൽ മോഡ്"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"നിർദ്ദേശിക്കുന്ന Bluetooth A2DP കോഡെക് ചാനൽ മോഡ് തിരഞ്ഞെടുക്കുക"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth ഓഡിയോ LDAC പ്ലേബാക്ക് നിലവാരം"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"നിർദ്ദേശിക്കുന്ന Bluetooth A2DP കോഡെക് LDAC പ്ലേബാക്ക് നിലവാരം തിരഞ്ഞെടുക്കുക"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"വയർലെസ് ഡിസ്‌പ്ലേ സർട്ടിഫിക്കേഷനായി ഓപ്‌ഷനുകൾ ദൃശ്യമാക്കുക"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"വൈഫൈ പിക്കറിൽ ഓരോ SSID RSSI പ്രകാരം കാണിക്കാൻ വൈഫൈ ലോഗിംഗ് നില വർദ്ധിപ്പിക്കുക"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"പ്രവർത്തനക്ഷമമായിരിക്കുമ്പോൾ, വൈഫൈ സിഗ്‌നൽ കുറവായിരിക്കുന്ന സമയത്ത് സെല്ലുലാറിലേക്ക് ഡാറ്റ കണക്ഷൻ മുഖേന കൈമാറുന്നതിൽ വൈഫൈ കൂടുതൽ പ്രവർത്തനക്ഷമമാകും"</string>
diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml
index 88d6517..f4d1ca3 100644
--- a/packages/SettingsLib/res/values-mn/arrays.xml
+++ b/packages/SettingsLib/res/values-mn/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP шалгахыг зөвхөн DRM контентэд ашиглах"</item>
     <item msgid="45075631231212732">"Байнга HDCP шалгахыг ашиглах"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Өгөгдмөл"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Өгөгдмөл"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Өгөгдмөл"</item>
-    <item msgid="8895532488906185219">"44.1 кГц"</item>
-    <item msgid="2909915718994807056">"48.0 кГц"</item>
-    <item msgid="3347287377354164611">"88.2 кГц"</item>
-    <item msgid="1234212100239985373">"96.0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Өгөгдмөл"</item>
-    <item msgid="4482862757811638365">"44.1 кГц"</item>
-    <item msgid="354495328188724404">"48.0 кГц"</item>
-    <item msgid="7329816882213695083">"88.2 кГц"</item>
-    <item msgid="6967397666254430476">"96.0 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Өгөгдмөл"</item>
-    <item msgid="5618929009984956469">"16 бит/жишээ"</item>
-    <item msgid="3412640499234627248">"24 бит/жишээ"</item>
-    <item msgid="121583001492929387">"32 бит/жишээ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Өгөгдмөл"</item>
-    <item msgid="4726688794884191540">"16 бит/жишээ"</item>
-    <item msgid="305344756485516870">"24 бит/жишээ"</item>
-    <item msgid="244568657919675099">"32 бит/жишээ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Өгөгдмөл"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Өгөгдмөл"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Давуу дууны чанар (990кб/с/909кб/с)"</item>
-    <item msgid="138837449700903545">"Стандарт (660кб/с/606кб/с)"</item>
-    <item msgid="4777177307869441982">"Давуу холболт (330кб/с/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Давуу дууны чанар (990кб/с/909кб/с)"</item>
-    <item msgid="9091111147684472529">"Стандарт (660кб/с/606кб/с)"</item>
-    <item msgid="3367904477834831032">"Давуу холболт (330кб/с/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Идэвхгүй"</item>
     <item msgid="1593289376502312923">"64000"</item>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index f412ac4..940e0b0 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Үүрэн холбооны датаг үргэлж идэвхтэй байлгана"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодлогч"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Давуу Bluetooth A2DP кодлогч сонгох"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудио жишээний үнэлгээ"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Давуу Bluetooth A2DP кодлогч жишээний үнэлгээ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Жишээ тутмын Bluetooth аудионы бит"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Жишээ тутмын давуу Bluetooth A2DP кодлогч битийг сонгох"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth аудио сувгийн горим"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Давуу Bluetooth A2DP кодлогч сувгийн горимыг сонгох"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth аудио LDAC тоглуулагчийн чанар"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Давуу Bluetooth A2DP кодлогч LDAC тоглуулагчийн чанарыг сонгох"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Утасгүй дэлгэцийн сертификатын сонголтыг харуулах"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi лог-н түвшинг нэмэгдүүлэх, Wi‑Fi Сонгогч дээрх SSID-д ногдох RSSI-г харуулах"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Идэвхжүүлсэн үед Wi‑Fi дохио сул бол дата холболтыг Үүрэн рүү шилжүүлэхдээ илүү идэвхтэй байх болно"</string>
diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml
index 9204c458..d8c8daf 100644
--- a/packages/SettingsLib/res/values-mr/arrays.xml
+++ b/packages/SettingsLib/res/values-mr/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"केवळ DRM सामग्रीसाठी HDCP तपासणी वापरा"</item>
     <item msgid="45075631231212732">"नेहमी HDCP तपासणी वापरा"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"डीफॉल्ट"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"डीफॉल्ट"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"डीफॉल्ट"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"डीफॉल्ट"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"डीफॉल्ट"</item>
-    <item msgid="5618929009984956469">"16 बिट/नमुना"</item>
-    <item msgid="3412640499234627248">"24 बिट/नमुना"</item>
-    <item msgid="121583001492929387">"32 बिट/नमुना"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"डीफॉल्ट"</item>
-    <item msgid="4726688794884191540">"16 बिट/नमुना"</item>
-    <item msgid="305344756485516870">"24 बिट/नमुना"</item>
-    <item msgid="244568657919675099">"32 बिट/नमुना"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"डीफॉल्ट"</item>
-    <item msgid="4106832974775067314">"मोनो"</item>
-    <item msgid="5571632958424639155">"स्टिरिओ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"डीफॉल्ट"</item>
-    <item msgid="8900559293912978337">"मोनो"</item>
-    <item msgid="8883739882299884241">"स्टिरिओ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"प्राधान्य दिलेली ध्वनी गुणवत्ता (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"मानक (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"प्राधान्य दिलेलेे कनेेक्शन (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"प्राधान्य दिलेली ध्वनी गुणवत्ता (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"मानक (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"प्राधान्य दिलेलेे कनेेक्शन (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"बंद"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 8b73d21..6c012c8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"सेल्युलर डेटा नेहमी सक्रिय"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"संपूर्ण आवाज अक्षम करा"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लूटूथ ऑडिओ कोडेक"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"प्राधान्यीकृत ब्लूटुथ A2DP कोडेक निवडा"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ब्लूटूथ ऑडिओ नमुना दर"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"प्राधान्यीकृत ब्लूटुथ A2DP कोडेक नमुना दर निवडा"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"प्रति नमुना ब्लूटुथ ऑडिओ बिट"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"प्रति नमुना प्राधान्यीकृत ब्लूटुथ A2DP कोडेक बिट निवडा"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ब्लूटूथ ऑडिओ चॅनेल मोड"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"प्राधान्यीकृत ब्लूटुथ A2DP कोडेक चॅनेल मोड निवडा"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ब्लूटुथ ऑडिओ LDAC प्लेबॅक गुणवत्ता"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"प्राधान्यीकृत ब्लूटुथ A2DP कोडेक LDAC प्लेबॅक गुणवत्ता निवडा"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"वायरलेस प्रदर्शन प्रमाणिकरणासाठी पर्याय दर्शवा"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"वाय-फाय लॉगिंग स्‍तर वाढवा, वाय-फाय निवडकामध्‍ये प्रति SSID RSSI दर्शवा"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"सक्षम केल्यास, वाय-फाय सिग्‍नल निम्‍न असताना, वाय-फाय डेटा कनेक्‍शन सेल्‍युलरवर बळपूर्वक स्विच करेल."</string>
diff --git a/packages/SettingsLib/res/values-ms/arrays.xml b/packages/SettingsLib/res/values-ms/arrays.xml
index 7ec6fab..5feff37 100644
--- a/packages/SettingsLib/res/values-ms/arrays.xml
+++ b/packages/SettingsLib/res/values-ms/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Gunakan penyemakan HDCP untuk kandungan DRM sahaja"</item>
     <item msgid="45075631231212732">"Sentiasa gunakan penyemakan HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Lalai"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Lalai"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Lalai"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Lalai"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Lalai"</item>
-    <item msgid="5618929009984956469">"16 bit/sampel"</item>
-    <item msgid="3412640499234627248">"24 bit/sampel"</item>
-    <item msgid="121583001492929387">"32 bit/sampel"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Lalai"</item>
-    <item msgid="4726688794884191540">"16 bit/sampel"</item>
-    <item msgid="305344756485516870">"24 bit/sampel"</item>
-    <item msgid="244568657919675099">"32 bit/sampel"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Lalai"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Lalai"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Kualiti bunyi dipilih (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Sambungan yang dipilih (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Kualiti bunyi dipilih (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Sambungan yang dipilih (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Mati"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index e57219c..acaab9d 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Data selular sentiasa aktif"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Lumpuhkan kelantangan mutlak"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Pilih Codec A2DP Bluetooth yang Diingini"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Kadar Sampel Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Pilih Kadar Sampel Codec A2DP Bluetooth yang Diingini"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bit Per Sampel Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Pilih Bit Per Sampel Codec A2DP Bluetooth yang Diingini"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Mod Saluran Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Pilih Mod Saluran Codec A2DP Bluetooth yang Diingini"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Kualiti Main Balik LDAC Audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Pilih Kualiti Main Balik LDAC Codec A2DP Bluetooth yang Diingini"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Tunjukkan pilihan untuk pensijilan paparan wayarles"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tingkatkan tahap pengelogan Wi-Fi, tunjuk setiap SSID RSSI dalam Pemilih Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Apabila didayakan, Wi-Fi akan menjadi lebih agresif dalam menyerahkan sambungan data ke Selular, apabila isyarat Wi-Fi rendah"</string>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index a43eb94..9e71ae5 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRMအကြောင်းအရာအတွက် HDCPစစ်ဆေးခြင်းကိုသုံးမည်"</item>
     <item msgid="45075631231212732">"HDCP checkingအားအမြဲသုံးပါ"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"မူရင်း"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"မူရင်း"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"မူရင်း"</item>
-    <item msgid="8895532488906185219">"၄၄.၁ kHz"</item>
-    <item msgid="2909915718994807056">"၄၈.၀ kHz"</item>
-    <item msgid="3347287377354164611">"၈၈.၂ kHz"</item>
-    <item msgid="1234212100239985373">"၉၆.၀ kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"မူရင်း"</item>
-    <item msgid="4482862757811638365">"၄၄.၁ kHz"</item>
-    <item msgid="354495328188724404">"၄၈.၀ kHz"</item>
-    <item msgid="7329816882213695083">"၈၈.၂ kHz"</item>
-    <item msgid="6967397666254430476">"၉၆.၀ kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"မူရင်း"</item>
-    <item msgid="5618929009984956469">"၁၆ bits/နမူနာ"</item>
-    <item msgid="3412640499234627248">"၂၄ bits/နမူနာ"</item>
-    <item msgid="121583001492929387">"၃၂ bits/နမူနာ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"မူရင်း"</item>
-    <item msgid="4726688794884191540">"၁၆ bits/နမူနာ"</item>
-    <item msgid="305344756485516870">"၂၄ bits/နမူနာ"</item>
-    <item msgid="244568657919675099">"၃၂ bits/နမူနာ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"မူရင်း"</item>
-    <item msgid="4106832974775067314">"မိုနို"</item>
-    <item msgid="5571632958424639155">"စတီရီယို"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"မူရင်း"</item>
-    <item msgid="8900559293912978337">"မိုနို"</item>
-    <item msgid="8883739882299884241">"စတီရီယို"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"ပိုမိုနှစ်သက်သည့် အသံအရည်အသွေး (၉၉၀kbps/၉၀၉kbps)"</item>
-    <item msgid="138837449700903545">"ပုံမှန် (၆၆၀kbps/၆၀၆kbps)"</item>
-    <item msgid="4777177307869441982">"ပိုမိုနှစ်သက်သည့် မြန်နှုန်း (၃၃၀kbps/၃၀၃kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"ပိုမိုနှစ်သက်သည့် အသံအရည်အသွေး (၉၉၀kbps/၉၀၉kbps)"</item>
-    <item msgid="9091111147684472529">"ပုံမှန် (၆၆၀kbps/၆၀၆kbps)"</item>
-    <item msgid="3367904477834831032">"ပိုမိုနှစ်သက်သည့် ချိတ်ဆက်မှု (၃၃၀kbps/၃၀၃kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ပိတ်ပါ"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 3b70cc3..2c976d0 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ဆဲလ်လူလာဒေတာ အမြဲတမ်းဖွင့်ထားသည်"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ဘလူးတုသ်အသံ ကိုးဒက်ခ်"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ်ကို ရွေးချယ်ပါ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ဘလူးတုသ်အသံနမူနာနှုန်း"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် အသံနမူနာနှုန်းကို ရွေးချယ်ပါ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"နမူနာတစ်ခုစီတွင် ပါဝင်သော ဘလူးတုသ်အသံပမာဏ Bits"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ပိုမိုနှစ်သက်သည့် နမူနာတစ်ခုစီတွင် ပါဝင်သော ဘလူးတုသ် A2DP ကိုးဒက်ခ် Bits ကို ရွေးပါ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ဘလူးတုသ်အသံချန်နယ်မုဒ်"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် ချန်နယ်မုဒ်ကိုရွေးချယ်ပါ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ဘလူးတုသ်အသံ LDAC ကြည့်ရန် အရည်အသွေး"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ်အသံ LDAC ကြည့်ရန် အရည်အသွေးကို ရွေးချယ်ပါ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ဖွင့်ထားလျှင်၊ Wi‑Fi မှ ဆယ်လူလာသို့ အချက်လက် ချိတ်ဆက်မှုအား လွှဲပြောင်းရာ၌ ပိုမိုထိရောက်ပါသည်၊ WIFI အားနည်းနေချိန်တွင်"</string>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index bf0b414..1d5d098 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Bruk HDCP-kontroll kun for DRM-innhold"</item>
     <item msgid="45075631231212732">"Bruk alltid HDCP-kontroll"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Standard"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Standard"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Standard"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Standard"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Standard"</item>
-    <item msgid="5618929009984956469">"16 bits/sample"</item>
-    <item msgid="3412640499234627248">"24 bits/sample"</item>
-    <item msgid="121583001492929387">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Standard"</item>
-    <item msgid="4726688794884191540">"16 bits/sample"</item>
-    <item msgid="305344756485516870">"24 bits/sample"</item>
-    <item msgid="244568657919675099">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Standard"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Standard"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Prioriter lydkvalitet (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Prioriter tilkobling (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Prioriter lydkvalitet (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Prioriter tilkobling (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Av"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 53e0127..02b742a 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata er alltid aktiv"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slå av funksjonen for absolutt volum"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Velg foretrukket A2DP-kodek for Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Samplefrekvens for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Velg foretrukket samplefrekvens fra A2DP-kodek for Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits per sample for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Velg foretrukket bits per sample fra A2DP-kodek for Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanalmodus for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Velg foretrukket kanalmodus fra A2DP-kodek for Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"LDAC-avspillingskvalitet for Bluetooth-lyd"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Velg foretrukket LDAC-avspillingskvalitet fra A2DP-kodek for Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Vis alternativer for sertifisering av trådløs skjerm"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Øk Wi-Fi-loggenivå – vis per SSID RSSI i Wi-Fi-velgeren"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Hvis dette slås på, overfører Wi-Fi-nettverket datatilkoblingen til mobil mer aggressivt når Wi-Fi-signalet er lavt"</string>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index d9cd5d2..19597ec 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM सामग्रीको लागि मात्र HDCP जाँचको प्रयोग गर्नुहोस्"</item>
     <item msgid="45075631231212732">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"पूर्वनिर्धारित मान"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"पूर्वनिर्धारित मान"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"पूर्वनिर्धारित मान"</item>
-    <item msgid="8895532488906185219">"४४.१ kHz"</item>
-    <item msgid="2909915718994807056">"४८.० kHz"</item>
-    <item msgid="3347287377354164611">"८८.२ kHz"</item>
-    <item msgid="1234212100239985373">"९६.० kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"पूर्वनिर्धारित मान"</item>
-    <item msgid="4482862757811638365">"४४.१ kHz"</item>
-    <item msgid="354495328188724404">"४८.० kHz"</item>
-    <item msgid="7329816882213695083">"८८.२ kHz"</item>
-    <item msgid="6967397666254430476">"९६.० kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"पूर्वनिर्धारित मान"</item>
-    <item msgid="5618929009984956469">"१६ बिट/नमूना"</item>
-    <item msgid="3412640499234627248">"२४ बिट/नमूना"</item>
-    <item msgid="121583001492929387">"३२ बिट/नमूना"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"पूर्वनिर्धारित मान"</item>
-    <item msgid="4726688794884191540">"१६ बिट/नमूना"</item>
-    <item msgid="305344756485516870">"२४ बिट/नमूना"</item>
-    <item msgid="244568657919675099">"३२ बिट/नमूना"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"पूर्वनिर्धारित मान"</item>
-    <item msgid="4106832974775067314">"मोनो"</item>
-    <item msgid="5571632958424639155">"स्टेरियो"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"पूर्वनिर्धारित मान"</item>
-    <item msgid="8900559293912978337">"मोनो"</item>
-    <item msgid="8883739882299884241">"स्टेरियो"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"रुचाइएको आवाजको गुणस्तर (९९०kbps/९०९kbps)"</item>
-    <item msgid="138837449700903545">"मानक (६६०kbps/६०६kbps)"</item>
-    <item msgid="4777177307869441982">"रुचाइएको जडान (३३०kbps/३०३kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"रुचाइएको आवाजको गुणस्तर (९९०kbps/९०९kbps)"</item>
-    <item msgid="9091111147684472529">"मानक (६६०kbps/६०६kbps)"</item>
-    <item msgid="3367904477834831032">"रुचाइएको जडान (३३०kbps/३०३kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"निष्क्रिय गर्नुहोस्"</item>
     <item msgid="1593289376502312923">"६४के"</item>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 311af42..12b3b15 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"सेलुलर डेटा सधैं सक्रिय"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ब्लुटुथ अडियोको कोडेक"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"रुचाइको ब्लुटुथ A2DP कोडेक चयन गर्नुहोस्"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ब्लुटुथ अडियोको नमूना दर"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"रुचाइको ब्लुटुथ A2DP कोडेक नमूना दर चयन गर्नुहोस्"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"प्रति नमूना ब्लुटुथ अडियोका बिटहरू"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"रुचाइको प्रति नमूना ब्लुटुथ A2DP कोडेकको बिट चयन गर्नुहोस्"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ब्लुटुथ अडियो च्यानलको मोड"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"रुचाइको ब्लुटुथ A2DP कोडेक च्यानलको मोड चयन गर्नुहोस्"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ब्लुटुथ अडियो LDAC प्लेब्याकको गुणस्तर"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"रुचाइको ब्लुटुथ A2DP कोडेक LDAC प्लेब्याकको गुणस्तर चयन गर्नुहोस्"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ताररहित प्रदर्शन प्रमाणीकरणका लागि विकल्पहरू देखाउनुहोस्"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi लग स्तर बढाउनुहोस्, Wi-Fi चयनकर्तामा प्रति SSID RSSI देखाइन्छ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Wi-Fi संकेत कम हुँदा, सक्षम जब गरिन्छ, Wi-Fi सेलुलर लागि डेटा जडान सुम्पनामा बढी आक्रामक हुनेछ"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index 6eb2b67..eaa8402 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP-controle alleen voor DRM-content gebruiken"</item>
     <item msgid="45075631231212732">"HDCP-controle altijd gebruiken"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Standaard"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Standaard"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Standaard"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Standaard"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Standaard"</item>
-    <item msgid="5618929009984956469">"16 bits per sample"</item>
-    <item msgid="3412640499234627248">"24 bits per sample"</item>
-    <item msgid="121583001492929387">"32 bits per sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Standaard"</item>
-    <item msgid="4726688794884191540">"16 bits per sample"</item>
-    <item msgid="305344756485516870">"24 bits per sample"</item>
-    <item msgid="244568657919675099">"32 bits per sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Standaard"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Standaard"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Voorkeur geluidskwaliteit (990/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standaard (660/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Voorkeursverbinding (330/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Voorkeur geluidskwaliteit (990/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standaard (660/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Voorkeursverbinding (330/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Uit"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 698ff09..9d53379 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobiele data altijd actief"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth-audiocodec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Voorkeur voor Bluetooth A2DP-codec selecteren"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bemonsteringsfrequentie (sample rate) van Bluetooth-audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Voorkeur voor bemonsteringsfrequentie (sample rate) voor Bluetooth A2DP-codec selecteren"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits per sample voor Bluetooth-audio"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Voorkeur voor bits per sample voor Bluetooth A2DP-codec selecteren"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanaalmodus voor Bluetooth-audio"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Voorkeur voor kanaalmodus voor Bluetooth A2DP-codec selecteren"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"LDAC-afspeelkwaliteit voor Bluetooth-audio"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Voorkeur voor LDAC-afspeelkwaliteit voor Bluetooth A2DP-codec selecteren"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Opties weergeven voor certificering van draadloze weergave"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Logniveau voor wifi verhogen, weergeven per SSID RSSI in wifi-kiezer"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Indien ingeschakeld, is wifi agressiever bij het overgeven van de gegevensverbinding aan mobiel wanneer het wifi-signaal zwak is"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index a53d534..7a100a9 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"ਕੇਵਲ DRM ਸਮੱਗਰੀ ਲਈ HDCP ਜਾਂਚ"</item>
     <item msgid="45075631231212732">"ਹਮੇਸਾਂ HDCP ਜਾਂਚ ਵਰਤੋ"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="5618929009984956469">"16 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="3412640499234627248">"24 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="121583001492929387">"32 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="4726688794884191540">"16 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="305344756485516870">"24 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="244568657919675099">"32 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="4106832974775067314">"ਮੋਨੋ"</item>
-    <item msgid="5571632958424639155">"ਸਟੀਰੀਓ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="8900559293912978337">"ਮੋਨੋ"</item>
-    <item msgid="8883739882299884241">"ਸਟੀਰੀਓ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"ਤਰਜੀਹੀ ਧੁਨੀ ਗੁਣਵੱਤਾ (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"ਮਿਆਰੀ ਗੁਣਵੱਤਾ (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"ਤਰਜੀਹੀ ਕਨੈਕਸ਼ਨ (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"ਤਰਜੀਹੀ ਧੁਨੀ ਗੁਣਵੱਤਾ (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"ਮਿਆਰੀ ਗੁਣਵੱਤਾ (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"ਤਰਜੀਹੀ ਕਨੈਕਸ਼ਨ (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ਬੰਦ"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index f824746..647e573 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ਸੈਲਿਊਲਰ ਡੇਟਾ ਹਮੇਸ਼ਾ ਕਿਰਿਆਸ਼ੀਲ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਵੌਲਿਊਮ ਨੂੰ ਅਯੋਗ ਬਣਾਓ"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਕੋਡੇਕ"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਚੁਣੋ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਨਮੂਨਾ ਦਰ"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਨਮੂਨਾ ਦਰ ਚੁਣੋ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਬਲੂਟੁੱਥ ਔਡੀਓ ਬਿੱਟ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਬਿੱਟ ਚੁਣੋ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਬਲੂਟੁੱਥ ਔਡੀਓ ਬਿਟਾਂ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਚੈਨਲ ਮੋਡ"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਚੈਨਲ ਮੋਡ ਚੁਣੋ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ਬਲੂਟੁੱਥ ਔਡੀਓ LDAC ਪਲੇਬੈਕ ਗੁਣਵੱਤਾ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ LDAC ਪਲੇਬੈਕ ਗੁਣਵੱਤਾ ਚੁਣੋ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ਵਾਇਰਲੈਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚੋਣਾਂ ਦਿਖਾਓ"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ਲੌਗਿੰਗ ਪੱਧਰ ਵਧਾਓ, Wi‑Fi Picker ਵਿੱਚ ਪ੍ਰਤੀ SSID RSSI ਦਿਖਾਓ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ਜਦੋਂ ਸਮਰਥਿਤ ਹੋਵੇ, ਤਾਂ Wi‑Fi ਸੈਲਿਊਲਰ ਨੂੰ ਡੈਟਾ ਕਨੈਕਸ਼ਨ ਹੈਂਡ ਓਵਰ ਕਰਨ ਵਿੱਚ ਵੱਧ ਅਗ੍ਰੈਸਿਵ ਹੋ ਜਾਏਗਾ, ਜਦੋਂ Wi‑Fi ਸਿਗਨਲ ਘੱਟ ਹੋਵੇ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 15a7b51..c813cad 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Użyj sprawdzania HDCP tylko w przypadku treści chronionych DRM"</item>
     <item msgid="45075631231212732">"Zawsze używaj sprawdzania HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Wartość domyślna"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Wartość domyślna"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Wartość domyślna"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Wartość domyślna"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Wartość domyślna"</item>
-    <item msgid="5618929009984956469">"16 bitów/próbkę"</item>
-    <item msgid="3412640499234627248">"24 bity/próbkę"</item>
-    <item msgid="121583001492929387">"32 bity/próbkę"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Wartość domyślna"</item>
-    <item msgid="4726688794884191540">"16 bitów/próbkę"</item>
-    <item msgid="305344756485516870">"24 bity/próbkę"</item>
-    <item msgid="244568657919675099">"32 bity/próbkę"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Wartość domyślna"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Wartość domyślna"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Preferowana jakość dźwięku (990 kb/s / 909 kb/s)"</item>
-    <item msgid="138837449700903545">"Standardowa (660 kb/s / 606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Preferowane połączenie (330 kb/s / 303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Preferowana jakość dźwięku (990 kb/s / 909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Standardowa (660 kb/s / 606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Preferowane połączenie (330 kb/s / 303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Wył."</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 9c841fa..20cb365 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dane komórkowe zawsze aktywne"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Wyłącz głośność bezwzględną"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodek dźwięku Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Wybierz preferowany kodek Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Dźwięk Bluetooth – współczynnik próbkowania"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Wybierz preferowany współczynnik próbkowania w kodeku Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Dźwięk Bluetooth – liczba bitów na próbkę"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Wybierz preferowaną liczbę bitów na próbkę w kodeku Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Dźwięk Bluetooth – tryb kanału"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Wybierz preferowany tryb kanału w kodeku Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Dźwięk Bluetooth – jakość dźwięku LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Wybierz preferowaną jakość dźwięku LDAC w kodeku Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaż opcje certyfikacji wyświetlacza bezprzewodowego"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zwiększ poziom rejestrowania Wi‑Fi, pokazuj według RSSI SSID w selektorze Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Po włączeniu połączenie danych będzie bardziej agresywnie przełączać się z Wi-Fi na sieć komórkową przy słabym sygnale Wi-Fi"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index 4d1f3bb..29e3f41 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Usar a verificação HDCP somente para conteúdo DRM"</item>
     <item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Padrão"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Padrão"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Padrão"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Padrão"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Padrão"</item>
-    <item msgid="5618929009984956469">"16 bits/amostra"</item>
-    <item msgid="3412640499234627248">"24 bits/amostra"</item>
-    <item msgid="121583001492929387">"32 bits/amostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Padrão"</item>
-    <item msgid="4726688794884191540">"16 bits/amostra"</item>
-    <item msgid="305344756485516870">"24 bits/amostra"</item>
-    <item msgid="244568657919675099">"32 bits/amostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Padrão"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Padrão"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qualidade de som preferencial (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Padrão (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Conexão preferencial (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qualidade de som preferencial (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Padrão (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Conexão preferencial (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Desativado"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 1c34317..5ad3cd9e 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dados da rede celular sempre ativos"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecione o codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostra do áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecione a taxa de amostra do codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra do áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecione os bits por amostra do codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selecione o modo de canal do codec Bluetooth A2DP preferencial"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualidade de reprodução LDAC de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selecione a qualidade de reprodução LDAC do codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando ativada, o Wi-Fi será mais agressivo em transferir a conexão de dados para celular, quando o sinal de Wi-Fi estiver fraco"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index d17701e..cf4d1c8 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Utilizar a verificação HDCP para conteúdo DRM apenas"</item>
     <item msgid="45075631231212732">"Utilizar sempre a verificação HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Predefinição"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Predefinição"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Predefinição"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Predefinição"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Predefinição"</item>
-    <item msgid="5618929009984956469">"16 bits/amostra"</item>
-    <item msgid="3412640499234627248">"24 bits/amostra"</item>
-    <item msgid="121583001492929387">"32 bits/amostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Predefinição"</item>
-    <item msgid="4726688794884191540">"16 bits/amostra"</item>
-    <item msgid="305344756485516870">"24 bits/amostra"</item>
-    <item msgid="244568657919675099">"32 bits/amostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Predefinição"</item>
-    <item msgid="4106832974775067314">"Monocromático"</item>
-    <item msgid="5571632958424639155">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Predefinição"</item>
-    <item msgid="8900559293912978337">"Monocromático"</item>
-    <item msgid="8883739882299884241">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qual. som preferida (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Padrão (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Ligação preferida (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qual. som preferida (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Padrão (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Ligação preferida (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Desativado"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a66ead0..f8ceac2 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dados móveis sempre ativados"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecionar Codec A2DP Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frequência de amostragem de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecionar Frequência de amostragem de codec A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
+    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostragem de áudio Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecionar Bits por amostra de codec A2DP Bluetooth preferido"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selecionar Modo de canal de codec A2DP Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualidade de reprodução LDAC de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selecionar Qualidade de reprodução LDAC de codec A2DP Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções da certificação de display sem fios"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de reg. de Wi-Fi, mostrar por RSSI de SSID no Selec. de Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Se estiver ativado, o Wi-Fi será mais agressivo ao transmitir a lig. de dados p/ a rede móvel quando o sinal Wi-Fi estiver fraco"</string>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index 4d1f3bb..29e3f41 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Usar a verificação HDCP somente para conteúdo DRM"</item>
     <item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Padrão"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Padrão"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Padrão"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Padrão"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Padrão"</item>
-    <item msgid="5618929009984956469">"16 bits/amostra"</item>
-    <item msgid="3412640499234627248">"24 bits/amostra"</item>
-    <item msgid="121583001492929387">"32 bits/amostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Padrão"</item>
-    <item msgid="4726688794884191540">"16 bits/amostra"</item>
-    <item msgid="305344756485516870">"24 bits/amostra"</item>
-    <item msgid="244568657919675099">"32 bits/amostra"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Padrão"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Padrão"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Estéreo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Qualidade de som preferencial (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Padrão (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Conexão preferencial (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Qualidade de som preferencial (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Padrão (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Conexão preferencial (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Desativado"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 1c34317..5ad3cd9e 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dados da rede celular sempre ativos"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecione o codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostra do áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecione a taxa de amostra do codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra do áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecione os bits por amostra do codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selecione o modo de canal do codec Bluetooth A2DP preferencial"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Qualidade de reprodução LDAC de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selecione a qualidade de reprodução LDAC do codec Bluetooth A2DP preferencial"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Mostrar opções de certificação de Display sem fio"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Aumentar o nível de registro do Wi-Fi; mostrar conforme o RSSI de SSID na Seleção de Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Quando ativada, o Wi-Fi será mais agressivo em transferir a conexão de dados para celular, quando o sinal de Wi-Fi estiver fraco"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index a6a0757..dc03065 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Utilizează verificarea HDCP numai pentru conținut DRM"</item>
     <item msgid="45075631231212732">"Utilizează întotdeauna verificarea HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Prestabilit"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Prestabilit"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Prestabilit"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Prestabilit"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Prestabilit"</item>
-    <item msgid="5618929009984956469">"16 biți/eșantion"</item>
-    <item msgid="3412640499234627248">"24 biți/eșantion"</item>
-    <item msgid="121583001492929387">"32 biți/eșantion"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Prestabilit"</item>
-    <item msgid="4726688794884191540">"16 biți/eșantion"</item>
-    <item msgid="305344756485516870">"24 biți/eșantion"</item>
-    <item msgid="244568657919675099">"32 biți/eșantion"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Prestabilit"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Prestabilit"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Cal. pref. sunet (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Conexiune preferată (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Cal. pref. sunet (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standard (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Conexiune preferată (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Dezactivată"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 512ba3a..8714926 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Conexiunea de date mobile este întotdeauna activată"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Dezactivați volumul absolut"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selectați codecul Bluetooth A2DP preferat"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Rată de eșantionare audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selectați rata de eșantionare codec Bluetooth A2DP preferată"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Biți audio Bluetooth per eșantion"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selectați biții codecului Bluetooth A2DP preferați per eșantion"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modul canal audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Selectați modul canal codec pentru Bluetooth A2DP preferat"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Calitatea redării Bluetooth audio LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Selectați calitatea redării LDAC a codecului pentru Bluetooth A2DP preferată"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Afișați opțiunile pentru certificarea Ecran wireless"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Măriți niv. de înr. prin Wi‑Fi, afișați în fcț. de SSID RSSI în Selectorul Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Când este activată, funcția Wi-Fi va fi mai agresivă la predarea conexiunii de date către mobil când semnalul Wi-Fi este slab"</string>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index 1080b01..bf192a5 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Использовать проверку HDCP только для DRM-контента"</item>
     <item msgid="45075631231212732">"Всегда использовать проверку HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"По умолчанию"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"По умолчанию"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"По умолчанию"</item>
-    <item msgid="8895532488906185219">"44,1 кГц"</item>
-    <item msgid="2909915718994807056">"48 кГц"</item>
-    <item msgid="3347287377354164611">"88,2 кГц"</item>
-    <item msgid="1234212100239985373">"96 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"По умолчанию"</item>
-    <item msgid="4482862757811638365">"44,1 кГц"</item>
-    <item msgid="354495328188724404">"48 кГц"</item>
-    <item msgid="7329816882213695083">"88,2 кГц"</item>
-    <item msgid="6967397666254430476">"96 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"По умолчанию"</item>
-    <item msgid="5618929009984956469">"16 бит/отсчет"</item>
-    <item msgid="3412640499234627248">"24 бит/отсчет"</item>
-    <item msgid="121583001492929387">"32 бит/отсчет"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"По умолчанию"</item>
-    <item msgid="4726688794884191540">"16 бит/отсчет"</item>
-    <item msgid="305344756485516870">"24 бит/отсчет"</item>
-    <item msgid="244568657919675099">"32 бит/отсчет"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"По умолчанию"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"По умолчанию"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Предпочтит. качество звука (990 кбит/с/909 кбит/с)"</item>
-    <item msgid="138837449700903545">"Стандартное (660 кбит/с/606 кбит/с)"</item>
-    <item msgid="4777177307869441982">"Предпочтит. соединение (330 кбит/с/303 кбит/с)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Предпочтит. качество звука (990 кбит/с/909 кбит/с)"</item>
-    <item msgid="9091111147684472529">"Стандартное (660 кбит/с/606 кбит/с)"</item>
-    <item msgid="3367904477834831032">"Предпочтит. соединение (330 кбит/с/303 кбит/с)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Выкл."</item>
     <item msgid="1593289376502312923">"64 КБ"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index bad2158..9da906b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Не отключать передачу данных"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Отключить абсолютный уровень громкости"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Аудиокодек для передачи через Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Выберите кодек A2DP для передачи через Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Частота дискретизации при передаче через Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Выберите частоту дискретизации для кодека A2DP (через Bluetooth)"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Глубина кодирования звука при передаче через Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Выберите глубину кодирования звука для кодека A2DP (через Bluetooth)"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим аудиоканала Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Выберите режим аудиоканала для кодека A2DP (через Bluetooth)"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Качество воспроизведения с кодеком A2DP (через Bluetooth)"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Выберите качество воспроизведения с кодеком A2DP (через Bluetooth)"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показывать параметры сертификации беспроводных мониторов"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"При выборе Wi‑Fi указывать в журнале RSSI для каждого SSID"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Принудительно переключаться на мобильную сеть, если сигнал Wi-Fi слабый"</string>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index afc125f..c9a5d12 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM අන්තර්ගත සඳහා පමණක් HDCP පරික්ෂාව භාවිතා කරන්න"</item>
     <item msgid="45075631231212732">"සැමවිටම HDCP පිරික්සුම භාවිතා කරන්න"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"පෙරනිමි"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"පෙරනිමි"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"පෙරනිමි"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"පෙරනිමි"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"පෙරනිමි"</item>
-    <item msgid="5618929009984956469">"බිටු 16/නියැදිය"</item>
-    <item msgid="3412640499234627248">"බිටු 24/නියැදිය"</item>
-    <item msgid="121583001492929387">"බිටු 32/නියැදිය"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"පෙරනිමි"</item>
-    <item msgid="4726688794884191540">"බිටු 16/නියැදිය"</item>
-    <item msgid="305344756485516870">"බිටු 24/නියැදිය"</item>
-    <item msgid="244568657919675099">"බිටු 32/නියැදිය"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"පෙරනිමි"</item>
-    <item msgid="4106832974775067314">"ඒකල"</item>
-    <item msgid="5571632958424639155">"ස්ටීරියෝ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"පෙරනිමි"</item>
-    <item msgid="8900559293912978337">"ඒකල"</item>
-    <item msgid="8883739882299884241">"ස්ටීරියෝ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"වඩා කැමති හඬ ගුණත්වය (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"සම්මත (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"වඩා කැමති සබැඳුම (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"වඩා කැමති හඬ ගුණත්වය (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"සම්මත (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"වඩා කැමති සබැඳුම (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ක්‍රියාවිරහිතය"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index fb6545b..1ff81e6 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"සෙලියුලර් දත්ත සැමවිට ක්‍රියාකාරීය"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"බ්ලූටූත් ශ්‍රව්‍ය Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"වඩා කැමති බ්ලූටූත් A2DP Codec තෝරන්න"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"බ්ලූටූත් ශ්‍රව්‍ය නියැදි අනුපාතය"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"වඩා කැමති බ්ලූටූත් A2DP Codec නියැදි අනුපාතය තෝරන්න"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"නියැදියකට බ්ලූටූත් ශ්‍රව්‍ය බිටු"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"නියැදියකට වඩා කැමති බ්ලූටූත් A2DP Codec බිටු තෝරන්න"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"බ්ලූටූත් ශ්‍රව්‍ය නාලිකා ප්‍රකාරය"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"වඩා කැමති බ්ලූටූත් A2DP Codec නාලිකා ප්‍රකාරය තෝරන්න"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"බ්ලූටූත් ශ්‍රව්‍ය LDAC පසුධාවන ගුණත්වය"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"වඩා කැමති බ්ලූටූත් A2DP Codec පසුධාවන ගුණත්වය තෝරන්න"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"නොරැහැන් සංදර්ශක සහතිකය සඳහා විකල්ප පෙන්වන්න"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ලොග් මට්ටම වැඩි කරන්න, Wi‑Fi තෝරනයෙහි SSID RSSI අනුව පෙන්වන්න"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"සබල විට Wi‑Fi සිග්නලය අඩු විට Wi‑Fi දත්ත සම්බන්ධතාවය සෙලියුලර් වෙත භාර දීමට වඩා ආක්‍රමණික වේ"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 66fabb2..3dd56cb 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Použiť kontrolu HDCP len pre obsah DRM"</item>
     <item msgid="45075631231212732">"Vždy používať kontrolu HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Predvolené"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Predvolené"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Predvolené"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Predvolené"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Predvolené"</item>
-    <item msgid="5618929009984956469">"16 bitov na vzorku"</item>
-    <item msgid="3412640499234627248">"24 bitov na vzorku"</item>
-    <item msgid="121583001492929387">"32 bitov na vzorku"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Predvolené"</item>
-    <item msgid="4726688794884191540">"16 bitov na vzorku"</item>
-    <item msgid="305344756485516870">"24 bitov na vzorku"</item>
-    <item msgid="244568657919675099">"32 bitov na vzorku"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Predvolené"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Predvolené"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Preferovanie kvality zvuku (990/909 kb/s)"</item>
-    <item msgid="138837449700903545">"Štandardné (660/606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Preferovanie pripojenia (330/303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Preferovanie kvality zvuku (990/909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Štandardné (660/606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Preferovanie pripojenia (330/303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Vypnuté"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 65de397..dfdc8f1 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilné dáta vždy aktívne"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázať absolútnu hlasitosť"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio – kodek"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Vyberte preferovaný kodek Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Audio – vzorkovacia frekvencia"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Zvoľte preferovanú vzorkovaciu frekvenciu kodeku Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Audio – počet bitov na vzorku"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Zvoľte preferovaný počet bitov na vzorky kodeku Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Audio – režim kanála"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Zvoľte preferovaný režim kanála kodeku Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Kvalita prehrávania LDAC Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Zvoľte preferovanú kvalitu prehrávania LDAC kodeku Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Zobraziť možnosti certifikácie bezdrôtového zobrazenia"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Zvýšiť úroveň denníkov Wi-Fi, zobrazovať podľa SSID RSSI pri výbere siete Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Keď túto možnosť zapnete, Wi-Fi bude agresívnejšie odovzdávať dát. pripoj. na mob. sieť vtedy, keď bude slabý signál Wi-Fi"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 6b6e0c8..d717308 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Preverjanje HDCP uporabi samo za vsebino DRM"</item>
     <item msgid="45075631231212732">"Vedno uporabi preverjanje HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Privzeto"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Privzeto"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Privzeto"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Privzeto"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Privzeto"</item>
-    <item msgid="5618929009984956469">"16 bitov/vzorec"</item>
-    <item msgid="3412640499234627248">"24 bitov/vzorec"</item>
-    <item msgid="121583001492929387">"32 bitov/vzorec"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Privzeto"</item>
-    <item msgid="4726688794884191540">"16 bitov/vzorec"</item>
-    <item msgid="305344756485516870">"24 bitov/vzorec"</item>
-    <item msgid="244568657919675099">"32 bitov/vzorec"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Privzeto"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Privzeto"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Prednostna kakovost zvoka (990/909 kb/s)"</item>
-    <item msgid="138837449700903545">"Standardno (660/606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Prednostna povezava (330/303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Prednostna kakovost zvoka (990/909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Standardno (660/606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Prednostna povezava (330/303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Izklopljeno"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index ef21240..af564f8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Prenos podatkov v mobilnih omrežjih je vedno aktiven"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogočanje absolutnega praga glasnosti"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Zvočni kodek za Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Izberite prednostni kodek A2DP za Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Hitrost vzorčenja zvoka prek Bluetootha"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Izberite prednostno hitrost vzorčenja za kodek A2DP za Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Število bitov na vzorec za zvok prek Bluetootha"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Izberite prednostno število bitov na vzorec za kodek A2DP za Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način zvočnega kanala prek Bluetootha"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Izberite prednostni način kanala za kodek A2DP za Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Kakovost predvajanja LDAC za zvok prek Bluetootha"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Izberite prednostno kakovost predvajanja LDAC za kodek A2DP za Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži možnosti za potrdilo brezžičnega zaslona"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povečaj raven zapis. dnev. za Wi-Fi; v izbir. Wi‑Fi-ja pokaži glede na SSID RSSI"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Če je ta možnost omogočena, Wi-Fi odločneje preda podatkovno povezavo mobilnemu omrežju, ko je signal Wi-Fi šibek"</string>
diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml
index e52b9fa..b91f694 100644
--- a/packages/SettingsLib/res/values-sq/arrays.xml
+++ b/packages/SettingsLib/res/values-sq/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Përdor kontrollin e HDCP-së vetëm për përmbajtjet DRM"</item>
     <item msgid="45075631231212732">"Përdor gjithmonë kontrollin e HDCP-së"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"I parazgjedhur"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"I parazgjedhur"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"I parazgjedhur"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"I parazgjedhur"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"I parazgjedhur"</item>
-    <item msgid="5618929009984956469">"16 bite/shembull"</item>
-    <item msgid="3412640499234627248">"24 bite/shembull"</item>
-    <item msgid="121583001492929387">"32 bite/shembull"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"I parazgjedhur"</item>
-    <item msgid="4726688794884191540">"16 bite/shembull"</item>
-    <item msgid="305344756485516870">"24 bite/shembull"</item>
-    <item msgid="244568657919675099">"32 bite/shembull"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"I parazgjedhur"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"I parazgjedhur"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Cilësia e preferuar e zërit (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standarde (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Lidhja e preferuar (330 kbps/303 kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Cilësia e preferuar e zërit (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standarde (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Lidhja e preferuar (330 kbps/303 kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Joaktiv"</item>
     <item msgid="1593289376502312923">"64 mijë"</item>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 56c36c0..1017cfc 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Të dhënat celulare gjithmonë aktive"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Çaktivizo volumin absolut"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeku Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Zgjidh kodekun e preferuar Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Shpejtësia e shembullit të Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Zgjidh shpejtësinë e preferuar të shembullit të kodekut Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bite për shembull Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Zgjidh bite për shembull të preferuar të kodekut Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Regjimi i kanalit Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Zgjidh regjimi e preferuar të kanalit të kodekut Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Cilësia e luajtjes së Bluetooth Audio LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Zgjidh cilësinë e preferuar të luajtjes të kodekut Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Shfaq opsionet për certifikimin e ekranit valor"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Rrit nivelin regjistrues të Wi‑Fi duke shfaqur SSID RSSI-në te Zgjedhësi i Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kur ky funksion aktivizohet, Wi‑Fi bëhet më agresiv në kalimin e lidhjes së të dhënave te rrjeti celular, në rastet kur sinjali Wi‑Fi është i dobët"</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index 8448c10..e767145 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Користи HDCP проверу само за DRM садржај"</item>
     <item msgid="45075631231212732">"Увек користи HDCP проверу"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Подразумевано"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Подразумевано"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Подразумевано"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Подразумевано"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Подразумевано"</item>
-    <item msgid="5618929009984956469">"16 битова по узорку"</item>
-    <item msgid="3412640499234627248">"24 бита по узорку"</item>
-    <item msgid="121583001492929387">"32 бита по узорку"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Подразумевано"</item>
-    <item msgid="4726688794884191540">"16 битова по узорку"</item>
-    <item msgid="305344756485516870">"24 бита по узорку"</item>
-    <item msgid="244568657919675099">"32 бита по узорку"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Подразумевано"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Подразумевано"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Жељени квалитет звука (990 kb/s/909 kb/s)"</item>
-    <item msgid="138837449700903545">"Стандардно (660 kb/s/606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Жељена веза (330 kb/s/303 kb/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Жељени квалитет звука (990 kb/s/909 kb/s)"</item>
-    <item msgid="9091111147684472529">"Стандардно (660 kb/s/606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Жељена веза (330 kb/s/303 kb/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Искључено"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index fd33eab..f6de46b 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Подаци за мобилне уређаје су увек активни"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Онемогући главно подешавање јачине звука"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудио кодек"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Изаберите жељени Bluetooth A2DP кодек"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Брзина узорковања за Bluetooth аудио"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Изаберите жељену брзину узорковања за Bluetooth A2DP кодек"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Битова по узорку за Bluetooth аудио"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Изаберите жељени број битова по узорку за Bluetooth A2DP кодек"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим канала за Bluetooth аудио"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Изаберите жељени режим канала за Bluetooth A2DP кодек"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Квалитет LDAC снимка за Bluetooth аудио"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Изаберите жељени квалитет LDAC снимка за Bluetooth A2DP кодек"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Приказ опција за сертификацију бежичног екрана"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Повећава ниво евидентирања за Wi‑Fi. Приказ по SSID RSSI-у у бирачу Wi‑Fi мреже"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Када се омогући, Wi‑Fi ће бити агресивнији при пребацивању мреже за пренос података на Мобилну, када је Wi‑Fi сигнал слаб"</string>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index e3e0103..fe395ac 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Använd bara HDCP-kontroll för DRM-innehåll"</item>
     <item msgid="45075631231212732">"Använd alltid HDCP-kontroll"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Standard"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Standard"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Standard"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Standard"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Standard"</item>
-    <item msgid="5618929009984956469">"16 bitar/sampling"</item>
-    <item msgid="3412640499234627248">"24 bitar/sampling"</item>
-    <item msgid="121583001492929387">"32 bitar/sampling"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Standard"</item>
-    <item msgid="4726688794884191540">"16 bitar/sampling"</item>
-    <item msgid="305344756485516870">"24 bitar/sampling"</item>
-    <item msgid="244568657919675099">"32 bitar/sampling"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Standard"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Standard"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Föredragen ljudkvalitet (990 kbit/s eller 909 kbit/s)"</item>
-    <item msgid="138837449700903545">"Standard (660 kbit/s eller 606 kbit/s)"</item>
-    <item msgid="4777177307869441982">"Föredragen anslutning (330 kbit/s eller 303 kbit/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Föredragen ljudkvalitet (990 kbit/s eller 909 kbit/s)"</item>
-    <item msgid="9091111147684472529">"Standard (660 kbit/s eller 606 kbit/s)"</item>
-    <item msgid="3367904477834831032">"Föredragen anslutning (330 kbit/s eller 303 kbit/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Av"</item>
     <item msgid="1593289376502312923">"64 kB"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 3b45fde..d68580b 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobildata alltid aktiverad"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inaktivera Absolute volume"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Ljudkodek för Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Välj föredragen A2DP-kodek för Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Samplingsfrekvens för Bluetooth-ljud"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Välj föredragen samplingsfrekvens för A2DP-kodek för Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Antar bitar per sampling för Bluetooth-ljud"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Välj föredraget antal bitar per sampling för A2DP-kodek för Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Kanalläge för Bluetooth-ljud"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Välj föredraget kanalläge för A2DP-kodek för Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Uppspelningskvalitet för Bluetooth-ljud via LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Välj föredragen uppspelningskvalitet för A2DP-kodek för Bluetooth via LDAC"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Visa certifieringsalternativ för Wi-Fi-skärmdelning"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Öka loggningsnivån för Wi-Fi, visa per SSID RSSI i Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"När funktionen har aktiverats kommer dataanslutningen lämnas över från Wi-Fi till mobilen på ett aggressivare sätt när Wi-Fi-signalen är svag"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index b4aeb1f..a7c4b63 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Tumia ukaguaji wa HDCP kwa maudhui ya DRM pekee"</item>
     <item msgid="45075631231212732">"Kila wakati tumia ukakuaji wa HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Chaguo-msingi"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Chaguo-msingi"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Chaguo-msingi"</item>
-    <item msgid="8895532488906185219">"kHz 44.1"</item>
-    <item msgid="2909915718994807056">"kHz 48.0"</item>
-    <item msgid="3347287377354164611">"kHz 88.2"</item>
-    <item msgid="1234212100239985373">"kHz 96.0"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Chaguo-msingi"</item>
-    <item msgid="4482862757811638365">"kHz 44.1"</item>
-    <item msgid="354495328188724404">"kHz 48.0"</item>
-    <item msgid="7329816882213695083">"kHz 88.2"</item>
-    <item msgid="6967397666254430476">"kHz 96.0"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Chaguo-msingi"</item>
-    <item msgid="5618929009984956469">"Biti 16 kwa kila sampuli"</item>
-    <item msgid="3412640499234627248">"Biti 24 kwa kila sampuli"</item>
-    <item msgid="121583001492929387">"Biti 32 kwa kila sampuli"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Chaguo-msingi"</item>
-    <item msgid="4726688794884191540">"Biti 16 kwa kila sampuli"</item>
-    <item msgid="305344756485516870">"Biti 24 kwa kila sampuli"</item>
-    <item msgid="244568657919675099">"Biti 32 kwa kila sampuli"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Chaguo-msingi"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Chaguo-msingi"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Ubora wa sauti unaopendelewa (kbps990/kbps909)"</item>
-    <item msgid="138837449700903545">"Ubora wa sauti wa kawaida (kbps660/kbps606)"</item>
-    <item msgid="4777177307869441982">"Muunganisho unaopendelewa (kbps330/kbps303)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Ubora wa sauti unaopendelewa (kbps990/kbps909)"</item>
-    <item msgid="9091111147684472529">"Ubora wa sauti wa kawaida (kbps660/kbps606)"</item>
-    <item msgid="3367904477834831032">"Muunganisho unaopendelewa (kbps330/kbps303)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Imezimwa"</item>
     <item msgid="1593289376502312923">"K64"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 563283b..1b2f876 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Data ya kifaa cha mkononi inatumika kila wakati"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zima sauti kamili"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeki ya Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Chagua Kodeki Unayopendelea ya A2DP ya Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Kiwango cha Sampuli ya Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Chagua Kiwango Unachopendelea cha Sampuli ya Kodeki ya A2DP ya Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Biti za Sauti ya Bluetooth kwa Kila Sampuli"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Chagua Biti za Kodeki ya A2DP ya Bluetooth Unazopendelea kwa Kila Sampuli"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hali ya Kituo cha Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Chagua Hali ya Kituo cha Kodeki ya A2DP ya Bluetooth Unayopendelea"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Ubora wa Kucheza LDAC ya Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Chagua Ubora Unaopendelea wa Kucheza LDAC ya Kodeki ya A2DP ya Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
+    <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hali ya Mkondo wa Sauti ya Bluetooth"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ikiwashwa, Wifi itakabidhi kwa hima muunganisho wa data kwa mtandao wa Simu za Mkononi, mawimbi ya Wifi yanapokuwa hafifu"</string>
diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml
index 9b3b1d4..efbe16d 100644
--- a/packages/SettingsLib/res/values-ta/arrays.xml
+++ b/packages/SettingsLib/res/values-ta/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM உள்ளடக்கத்திற்கு மட்டும் HDCP சோதனையைப் பயன்படுத்து"</item>
     <item msgid="45075631231212732">"HDCP சரிபார்ப்பை எப்போதும் பயன்படுத்து"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"இயல்பு"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"இயல்பு"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"இயல்பு"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"இயல்பு"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"இயல்பு"</item>
-    <item msgid="5618929009984956469">"16 பிட்கள்/சாம்பிள்"</item>
-    <item msgid="3412640499234627248">"24 பிட்கள்/சாம்பிள்"</item>
-    <item msgid="121583001492929387">"32 பிட்கள்/சாம்பிள்"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"இயல்பு"</item>
-    <item msgid="4726688794884191540">"16 பிட்கள்/சாம்பிள்"</item>
-    <item msgid="305344756485516870">"24 பிட்கள்/சாம்பிள்"</item>
-    <item msgid="244568657919675099">"32 பிட்கள்/சாம்பிள்"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"இயல்பு"</item>
-    <item msgid="4106832974775067314">"மோனோ"</item>
-    <item msgid="5571632958424639155">"ஸ்டீரியோ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"இயல்பு"</item>
-    <item msgid="8900559293912978337">"மோனோ"</item>
-    <item msgid="8883739882299884241">"ஸ்டீரியோ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"ஒலித் தரம் (பரிந்துரை) (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"நிலையானது (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"இணைப்பு (பரிந்துரை) (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"ஒலித் தரம் (பரிந்துரை) (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"நிலையானது (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"இணைப்பு (பரிந்துரை) (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"முடக்கு"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index c628d5e..a94dd3a 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"செல்லுலார் தரவு எப்போதும் இயக்கத்தில்"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"புளூடூத் ஆடியோ கோடெக்"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"பரிந்துரைக்கப்படும் புளூடூத் A2DP கோடெக்கைத் தேர்ந்தெடுக்கவும்"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"புளூடூத் ஆடியோ சாம்பிள் ரேட்"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"பரிந்துரைக்கப்படும் புளூடூத் A2DP கோடெக் சாம்பிள் ரேட்டைத் தேர்ந்தெடுக்கவும்"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"புளூடூத் ஆடியோ பிட்கள்/சாம்பிள்"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ஒரு சாம்பிளுக்குப் பரிந்துரைக்கப்படும் புளூடூத் A2DP கோடெக் பிட்களைத் தேர்ந்தெடுக்கவும்"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"புளூடூத் ஆடியோ சேனல் பயன்முறை"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"பரிந்துரைக்கப்படும் புளூடூத் A2DP கோடெக் சேனல் பயன்முறையைத் தேர்ந்தெடுக்கவும்"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"புளூடூத் ஆடியோ LDAC வீடியோவின் தரம்"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"பரிந்துரைக்கப்படும் புளூடூத் A2DP கோடெக் LDAC வீடியோவின் தரத்தைத் தேர்ந்தெடுக்கவும்"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wifi நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"இயக்கப்பட்டதும், வைஃபை சிக்னல் குறையும் போது, வைஃபை முழுமையாக ஒத்துழைக்காமல் இருப்பதால் செல்லுலாரின் தரவு இணைப்புக்கு மாறும்"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index beb705a..bee6402 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"DRM కంటెంట్‌కు మాత్రమే HDCP తనిఖీని ఉపయోగించండి"</item>
     <item msgid="45075631231212732">"ఎప్పటికీ HDCP తనిఖీని ఉపయోగించు"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"డిఫాల్ట్"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"డిఫాల్ట్"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"డిఫాల్ట్"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"డిఫాల్ట్"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"డిఫాల్ట్"</item>
-    <item msgid="5618929009984956469">"16 బిట్‌లు/నమూనా"</item>
-    <item msgid="3412640499234627248">"24 బిట్‌లు/నమూనా"</item>
-    <item msgid="121583001492929387">"32 బిట్‌లు/నమూనా"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"డిఫాల్ట్"</item>
-    <item msgid="4726688794884191540">"16 బిట్‌లు/నమూనా"</item>
-    <item msgid="305344756485516870">"24 బిట్‌లు/నమూనా"</item>
-    <item msgid="244568657919675099">"32 బిట్‌లు/నమూనా"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"డిఫాల్ట్"</item>
-    <item msgid="4106832974775067314">"మోనో"</item>
-    <item msgid="5571632958424639155">"స్టీరియో"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"డిఫాల్ట్"</item>
-    <item msgid="8900559293912978337">"మోనో"</item>
-    <item msgid="8883739882299884241">"స్టీరియో"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"ప్రాధాన్య శబ్ద నాణ్యత (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"ప్రామాణికం (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"ప్రాధాన్య కనెక్షన్ (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"ప్రాధాన్య శబ్ద నాణ్యత (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"ప్రామాణికం (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"ప్రాధాన్య కనెక్షన్ (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ఆఫ్"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 0d21371..d96e412 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ఎల్లప్పుడూ సెల్యులార్ డేటాను సక్రియంగా ఉంచు"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"బ్లూటూత్ ఆడియో కోడెక్"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ప్రాధాన్య బ్లూటూత్ A2DP కోడెక్‌ను ఎంచుకోండి"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"బ్లూటూత్ ఆడియో నమూనా రేట్"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ప్రాధాన్య బ్లూటూత్ A2DP కోడెక్ నమూనా రేట్‌ను ఎంచుకోండి"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ఒక్కో నమూనాకు బ్లూటూత్ ఆడియో బిట్‌లు"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ఒక్కో నమూనాకు ప్రాధాన్య బ్లూటూత్ A2DP కోడెక్ బిట్‌లను ఎంచుకోండి"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"బ్లూటూత్ ఆడియో ఛానెల్ మోడ్"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ప్రాధాన్య బ్లూటూత్ A2DP కోడెక్ ఛానెల్ మోడ్‌ను ఎంచుకోండి"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"బ్లూటూత్ ఆడియో LDAC ప్లేబ్యాక్ నాణ్యత"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"ప్రాధాన్య బ్లూటూత్ A2DP కోడెక్ LDAC ప్లేబ్యాక్ నాణ్యతను ఎంచుకోండి"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"వైర్‌లెస్ ప్రదర్శన ప్రమాణపత్రం కోసం ఎంపికలను చూపు"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ప్రారంభించబడినప్పుడు, Wi‑Fi సిగ్నల్ బలహీనంగా ఉంటే డేటా కనెక్షన్‌ను సెల్యులార్‌కి మార్చేలా Wi‑Fiపై మరింత తీవ్ర ఒత్తిడి కలుగుతుంది"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 1032337..690ce0c 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"ใช้การตรวจสอบ HDCP สำหรับเนื้อหา DRM เท่านั้น"</item>
     <item msgid="45075631231212732">"ใช้การตรวจสอบ HDCP เสมอ"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ค่าเริ่มต้น"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ค่าเริ่มต้น"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ค่าเริ่มต้น"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ค่าเริ่มต้น"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ค่าเริ่มต้น"</item>
-    <item msgid="5618929009984956469">"16 บิต/ตัวอย่าง"</item>
-    <item msgid="3412640499234627248">"24 บิต/ตัวอย่าง"</item>
-    <item msgid="121583001492929387">"32 บิต/ตัวอย่าง"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ค่าเริ่มต้น"</item>
-    <item msgid="4726688794884191540">"16 บิต/ตัวอย่าง"</item>
-    <item msgid="305344756485516870">"24 บิต/ตัวอย่าง"</item>
-    <item msgid="244568657919675099">"32 บิต/ตัวอย่าง"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ค่าเริ่มต้น"</item>
-    <item msgid="4106832974775067314">"โมโน"</item>
-    <item msgid="5571632958424639155">"สเตอริโอ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ค่าเริ่มต้น"</item>
-    <item msgid="8900559293912978337">"โมโน"</item>
-    <item msgid="8883739882299884241">"สเตอริโอ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"คุณภาพเสียงที่ต้องการ (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"มาตรฐาน (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"การเชื่อมต่อที่ต้องการ (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"คุณภาพเสียงที่ต้องการ (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"มาตรฐาน (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"การเชื่อมต่อที่ต้องการ (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ปิด"</item>
     <item msgid="1593289376502312923">"64 K"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 60d91b5..3d8af85 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"เปิดใช้ข้อมูลมือถือเสมอ"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ตัวแปลงรหัสเสียงบลูทูธ"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"เลือกตัวแปลงรหัสบลูทูธ A2DP ที่ต้องการ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"อัตราตัวอย่างเสียงบลูทูธ"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"เลือกอัตราตัวอย่างของตัวแปลงรหัสบลูทูธ A2DP ที่ต้องการ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"บิตต่อตัวอย่างของเสียงบลูทูธ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"เลือกบิตต่อตัวอย่างของตัวแปลงรหัสบลูทูธ A2DP ที่ต้องการ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"โหมดช่องสัญญาณเสียงบลูทูธ"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"เลือกโหมดช่องสัญญาณเสียงของตัวแปลงรหัสบลูทูธ A2DP ที่ต้องการ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"คุณภาพการเล่นเสียงบลูทูธ LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"เลือกคุณภาพการเล่น LDAC ของตัวแปลงรหัสบลูทูธ A2DP ที่ต้องการ"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"แสดงตัวเลือกสำหรับการรับรองการแสดงผล แบบไร้สาย"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"เมื่อเปิดใช้แล้ว Wi-Fi จะส่งผ่านการเชื่อมต่อข้อมูลไปยังเครือข่ายมือถือในทันทีที่พบสัญญาณ Wi-Fi อ่อน"</string>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index c0e9843..c67be8a 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Gamitin lang ang pagsusuring HDCP para sa nilalamang DRM"</item>
     <item msgid="45075631231212732">"Palaging gumamit ng pagsusuring HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Default"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Default"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Default"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Default"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Default"</item>
-    <item msgid="5618929009984956469">"16 bits/sample"</item>
-    <item msgid="3412640499234627248">"24 bits/sample"</item>
-    <item msgid="121583001492929387">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Default"</item>
-    <item msgid="4726688794884191540">"16 bits/sample"</item>
-    <item msgid="305344756485516870">"24 bits/sample"</item>
-    <item msgid="244568657919675099">"32 bits/sample"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Default"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Default"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Gustong kalidad tunog (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Karaniwan (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Gustong koneksyon (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Gustong kalidad tunog (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Karaniwan (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Gustong koneksyon (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"I-off"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 58781b2..a7ccc2a 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Palaging aktibo ang cellular data"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"I-disable ang absolute volume"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Audio Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Piliin ang Gustong Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Sample na Rate ng Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Piliin ang Gustong Sample na Rate ng Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits Per Sample ng Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Piliin ang Gustong Bits Per Sample ng Bluetooth A2DP Codec"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Channel Mode ng Bluetooth Audio"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Piliin ang Gustong Channel Mode ng Bluetooth A2DP Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Playback Quality ng Bluetooth Audio LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Piliin ang Gustong Playback Quality ng Bluetooth A2DP Codec LDAC"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Ipakita ang mga opsyon para sa certification ng wireless display"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Pataasin ang antas ng Wi‑Fi logging, ipakita sa bawat SSID RSSI sa Wi‑Fi Picker"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kapag naka-enable, mas magiging agresibo ang Wi‑Fi sa paglipat ng koneksyon ng data sa Cellular, kapag mahina ang signal ng Wi‑Fi"</string>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index ee668c7..00cf236 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP denetimini yalnızca DRM içeriği için kullan"</item>
     <item msgid="45075631231212732">"HDCP denetimini her zaman kullan"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Varsayılan"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Varsayılan"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Varsayılan"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Varsayılan"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Varsayılan"</item>
-    <item msgid="5618929009984956469">"16 bit/örnek"</item>
-    <item msgid="3412640499234627248">"24 bit/örnek"</item>
-    <item msgid="121583001492929387">"32 bit/örnek"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Varsayılan"</item>
-    <item msgid="4726688794884191540">"16 bit/örnek"</item>
-    <item msgid="305344756485516870">"24 bit/örnek"</item>
-    <item msgid="244568657919675099">"32 bit/örnek"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Varsayılan"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Varsayılan"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Ses kalitesi öncelikli (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Standart (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Bağlantı öncelikli (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Ses kalitesi öncelikli (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Standart (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Bağlantı öncelikli (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Kapalı"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index b5c081a..a452481 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Hücresel veri her zaman etkin"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mutlak sesi iptal et"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth Ses Codec\'i"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Tercih Edilen Bluetooth A2DP Codec\'ini Seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth Ses Örnek Hızı"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Tercih Edilen Bluetooth A2DP Codec\'i Örnek Hızını Seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth Ses Örnek Başına Bit Sayısı"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Tercih Edilen Bluetooth A2DP Codec\'i Örnek Başına Bit Sayısını Seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth Ses Kanalı Modu"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Tercih Edilen Bluetooth A2DP Codec\'i Kanal Modunu Seçin"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth Ses LDAC Oynatma Kalitesi"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Tercih Edilen Bluetooth A2DP Codec\'i LDAC Oynatma Kalitesini Seçin"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Kablosuz ekran sertifikası seçeneklerini göster"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Kablosuz günlük kaydı seviyesini artır. Kablosuz Seçici\'de her bir SSID RSSI için göster."</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Etkinleştirildiğinde, Kablosuz ağ sinyali zayıfken veri bağlantısının Hücresel ağa geçirilmesinde daha agresif olunur"</string>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 91a6d6f..dd661c4 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Використовувати перевірку HDCP лише для вмісту, захищеного DRM"</item>
     <item msgid="45075631231212732">"Завжди використовувати перевірку HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"За умовчанням"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"За умовчанням"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"За умовчанням"</item>
-    <item msgid="8895532488906185219">"44,1 кГц"</item>
-    <item msgid="2909915718994807056">"48 кГц"</item>
-    <item msgid="3347287377354164611">"88,2 кГц"</item>
-    <item msgid="1234212100239985373">"96 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"За умовчанням"</item>
-    <item msgid="4482862757811638365">"44,1 кГц"</item>
-    <item msgid="354495328188724404">"48 кГц"</item>
-    <item msgid="7329816882213695083">"88,2 кГц"</item>
-    <item msgid="6967397666254430476">"96 кГц"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"За умовчанням"</item>
-    <item msgid="5618929009984956469">"16 бітів на зразок"</item>
-    <item msgid="3412640499234627248">"24 біти на зразок"</item>
-    <item msgid="121583001492929387">"32 біти на зразок"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"За умовчанням"</item>
-    <item msgid="4726688794884191540">"16 бітів на зразок"</item>
-    <item msgid="305344756485516870">"24 біти на зразок"</item>
-    <item msgid="244568657919675099">"32 біти на зразок"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"За умовчанням"</item>
-    <item msgid="4106832974775067314">"Моно"</item>
-    <item msgid="5571632958424639155">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"За умовчанням"</item>
-    <item msgid="8900559293912978337">"Моно"</item>
-    <item msgid="8883739882299884241">"Стерео"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Реком. якість звуку (990 та 909 Кбіт/с)"</item>
-    <item msgid="138837449700903545">"Стандартна якість (660 і 606 Кбіт/с)"</item>
-    <item msgid="4777177307869441982">"Рекоменд. з’єднання (330 і 303 Кбіт/с)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Реком. якість звуку (990 та 909 Кбіт/с)"</item>
-    <item msgid="9091111147684472529">"Стандартна якість (660 і 606 Кбіт/с)"</item>
-    <item msgid="3367904477834831032">"Рекоменд. з’єднання (330 і 303 Кбіт/с)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Вимкнено"</item>
     <item msgid="1593289376502312923">"64 Кб"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index bafd8b6..b67c7c9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Не вимикати передавання даних"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Вимкнути абсолютну гучність"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек для аудіо Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Виберіть кодек Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Частота вибірки для аудіо Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Виберіть частоту вибірки для кодека Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Кількість бітів на зразок для аудіо Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Виберіть кількість бітів на зразок для кодека Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим каналу для аудіо Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Виберіть режим каналу для кодека Bluetooth A2DP"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Якість відтворення аудіо Bluetooth LDAC"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Виберіть якість відтворення для кодека Bluetooth A2DP"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Показати параметри сертифікації бездротового екрана"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Показувати в журналі RSSI для кожного SSID під час вибору Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Примусово перемикатися на мобільну мережу, коли сигнал Wi-Fi слабкий"</string>
diff --git a/packages/SettingsLib/res/values-ur/arrays.xml b/packages/SettingsLib/res/values-ur/arrays.xml
index d7dd3d2..d970f19 100644
--- a/packages/SettingsLib/res/values-ur/arrays.xml
+++ b/packages/SettingsLib/res/values-ur/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"‏HDCP چیکنگ صرف DRM مواد کیلئے استعمال کریں"</item>
     <item msgid="45075631231212732">"‏ہمیشہ HDCP چیکنگ استعمال کریں"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"ڈیفالٹ"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"ڈیفالٹ"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"ڈیفالٹ"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"ڈیفالٹ"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"ڈیفالٹ"</item>
-    <item msgid="5618929009984956469">"16 بٹس/نمونہ"</item>
-    <item msgid="3412640499234627248">"24 بٹس/نمونہ"</item>
-    <item msgid="121583001492929387">"32 بٹس/نمونہ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"ڈیفالٹ"</item>
-    <item msgid="4726688794884191540">"16 بٹس/نمونہ"</item>
-    <item msgid="305344756485516870">"24 بٹس/نمونہ"</item>
-    <item msgid="244568657919675099">"32 بٹس/نمونہ"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"ڈیفالٹ"</item>
-    <item msgid="4106832974775067314">"مونو"</item>
-    <item msgid="5571632958424639155">"اسٹیریو"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"ڈیفالٹ"</item>
-    <item msgid="8900559293912978337">"مونو"</item>
-    <item msgid="8883739882299884241">"اسٹیریو"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"‏آواز کا معیار ترجیحی (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"‏معیاری (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"‏کنکشن ترجیحی (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"‏آواز کا معیار ترجیحی (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"‏معیاری (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"‏کنکشن ترجیحی (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"آف"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index ce27df8..d4ad6b9 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"سیلولر ڈیٹا کو ہمیشہ فعال رکھیں"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"بلوٹوتھ آڈیو کوڈیک"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"‏ترجیحی بلوٹوتھ A2DP کوڈیک منتخب کریں"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"بلوٹوتھ آڈیو کے نمونے کی شرح"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"‏ترجیحی بلوٹوتھ A2DP کوڈیک نمونے کی شرح منتخب کریں"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"بلوٹوتھ آڈیو بٹس فی نمونہ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"‏ترجیحی بلو ٹوتھ A2DP کوڈیک بٹس فی نمونہ منتخب کریں"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"بلوٹوتھ آڈیو چینل موڈ"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"‏ترجیحی بلوٹوتھ A2DP کوڈیک چینل موڈ منتخب کریں"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"‏بلوٹوتھ آڈیو LDAC پلے بیک کا معیار"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"‏ترجیحی بلوٹوتھ A2DP کوڈیک LDAC پلے بیک کا معیار منتخب کریں"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"وائرلیس ڈسپلے سرٹیفیکیشن کیلئے اختیارات دکھائیں"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"‏Wi‑Fi لاگنگ لیول میں اضافہ کریں، Wi‑Fi منتخب کنندہ میں فی SSID RSSI دکھائیں"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"‏فعال ہونے پر، جب Wi‑Fi سگنل کمزور ہوگا تو Wi‑Fi سیلولر پر ڈیٹا کنکشن بھیجنے کیلئے مزید جارحانہ کاروائی کرے گا۔"</string>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index 11b3de7..f784021 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"HDCP tekshiruvi faqat DRM kontent uchun ishlatilsin"</item>
     <item msgid="45075631231212732">"Har doim HDCP tekshiruvidan foydalanilsin"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Standart"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Standart"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Standart"</item>
-    <item msgid="8895532488906185219">"44.1 kGs"</item>
-    <item msgid="2909915718994807056">"48.0 kGs"</item>
-    <item msgid="3347287377354164611">"88.2 kGs"</item>
-    <item msgid="1234212100239985373">"96.0 kGs"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Standart"</item>
-    <item msgid="4482862757811638365">"44.1 kGs"</item>
-    <item msgid="354495328188724404">"48.0 kGs"</item>
-    <item msgid="7329816882213695083">"88.2 kGs"</item>
-    <item msgid="6967397666254430476">"96.0 kGs"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Standart"</item>
-    <item msgid="5618929009984956469">"16 bit/namuna"</item>
-    <item msgid="3412640499234627248">"24 bit/namuna"</item>
-    <item msgid="121583001492929387">"32 bit/namuna"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Standart"</item>
-    <item msgid="4726688794884191540">"16 bit/namuna"</item>
-    <item msgid="305344756485516870">"24 bit/namuna"</item>
-    <item msgid="244568657919675099">"32 bit/namuna"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Standart"</item>
-    <item msgid="4106832974775067314">"Mono"</item>
-    <item msgid="5571632958424639155">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Standart"</item>
-    <item msgid="8900559293912978337">"Mono"</item>
-    <item msgid="8883739882299884241">"Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"O‘zingizga ma’qul ovoz sifati (990/909 kbit/s)"</item>
-    <item msgid="138837449700903545">"Standart (660/606 kbit/s)"</item>
-    <item msgid="4777177307869441982">"O‘zingizga ma’qul ulanish (330/303 kbit/s)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"O‘zingizga ma’qul ovoz sifati (990/909 kbit/s)"</item>
-    <item msgid="9091111147684472529">"Standart (660/606 kbit/s)"</item>
-    <item msgid="3367904477834831032">"O‘zingizga ma’qul ulanish (330/303 kbit/s)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"O‘chiq"</item>
     <item msgid="1593289376502312923">"64 KB"</item>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 6efc6c4..f50f36b 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobil internet o‘chirilmasin"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Ovoz balangligining mutlaq darajasini o‘chirib qo‘yish"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth audio kodeki"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"O‘zingizga ma’qul Bluetooth A2DP kodekini tanlang"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth audio namunasi chastotasi"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"O‘zingizga ma’qul Bluetooth A2DP kodek namunasi chastotasini tanlang"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio namunasidagi bitlar soni"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"O‘zingizga ma’qul Bluetooth A2DP kodek namunasidagi bitlar sonini tanlang"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Bluetooth audio kanali rejimi"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"O‘zingizga ma’qul Bluetooth A2DP kodek kanali rejimini tanlang"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Bluetooth audio LDAC ijrosi sifati"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"O‘zingizga ma’qul Bluetooth A2DP kodek LDAC ijrosi sifatini tanlang"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Simsiz monitorlarni sertifikatlash parametrini ko‘rsatish"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi-Fi ulanishini tanlashda har bir SSID uchun jurnalda ko‘rsatilsin"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Agar ushbu funksiya yoqilsa, Wi-Fi signali past bo‘lganda internetga ulanish majburiy ravishda mobil internetga o‘tkaziladi."</string>
@@ -240,7 +248,7 @@
     <string name="enable_opengl_traces_title" msgid="6790444011053219871">"OpenGL trassasini yoqish"</string>
     <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Audio uzatishni o‘ch. qo‘yish (USB)"</string>
     <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Tashqi USB qurilmaga avto-yo‘naltirishni o‘ch. qo‘yish"</string>
-    <string name="debug_layout" msgid="5981361776594526155">"Elementlar chegarasini ko‘rsatish"</string>
+    <string name="debug_layout" msgid="5981361776594526155">"Elementlar hoshiyasi"</string>
     <string name="debug_layout_summary" msgid="2001775315258637682">"Klip, maydon va h.k. chegaralarini ko‘rsatish"</string>
     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"O‘ngdan chapga qarab yozish"</string>
     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Barcha tillarda o‘ngdan chapga qarab yozish"</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index e7dbd4e..21bbf0a 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Chỉ sử dụng kiểm tra HDCP cho nội dung DRM"</item>
     <item msgid="45075631231212732">"Luôn sử dụng kiểm tra HDCP"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Mặc định"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Mặc định"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Mặc định"</item>
-    <item msgid="8895532488906185219">"44,1 kHz"</item>
-    <item msgid="2909915718994807056">"48,0 kHz"</item>
-    <item msgid="3347287377354164611">"88,2 kHz"</item>
-    <item msgid="1234212100239985373">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Mặc định"</item>
-    <item msgid="4482862757811638365">"44,1 kHz"</item>
-    <item msgid="354495328188724404">"48,0 kHz"</item>
-    <item msgid="7329816882213695083">"88,2 kHz"</item>
-    <item msgid="6967397666254430476">"96,0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Mặc định"</item>
-    <item msgid="5618929009984956469">"16 bit/mẫu"</item>
-    <item msgid="3412640499234627248">"24 bit/mẫu"</item>
-    <item msgid="121583001492929387">"32 bit/mẫu"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Mặc định"</item>
-    <item msgid="4726688794884191540">"16 bit/mẫu"</item>
-    <item msgid="305344756485516870">"24 bit/mẫu"</item>
-    <item msgid="244568657919675099">"32 bit/mẫu"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Mặc định"</item>
-    <item msgid="4106832974775067314">"Đơn âm"</item>
-    <item msgid="5571632958424639155">"Âm thanh nổi"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Mặc định"</item>
-    <item msgid="8900559293912978337">"Đơn âm"</item>
-    <item msgid="8883739882299884241">"Âm thanh nổi"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"C.lượng â.thanh ưu tiên (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Tiêu chuẩn (660kb/giây/606kb/giây)"</item>
-    <item msgid="4777177307869441982">"Kết nối được ưu tiên (330kb/giây/303kb/giây)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"C.lượng â.thanh ưu tiên (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Tiêu chuẩn (660kb/giây/606kb/giây)"</item>
-    <item msgid="3367904477834831032">"Kết nối được ưu tiên (330kb/giây/303kb/giây)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Tắt"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 5822f18..85be70e 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Dữ liệu di động luôn hoạt động"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Vô hiệu hóa âm lượng tuyệt đối"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec âm thanh Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Chọn Codec A2DP Bluetooth ưu tiên"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Tốc độ lấy mẫu âm thanh Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Chọn tốc độ lấy mẫu Codec A2DP Bluetooth ưu tiên"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Số bit âm thanh Bluetooth mỗi mẫu"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Chọn số bit Codec A2DP Bluetooth ưu tiên mỗi mẫu"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Chế độ kênh âm thanh Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Chọn chế độ kênh Codec A2DP Bluetooth ưu tiên"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Chất lượng phát lại LDAC Âm thanh Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Chọn chất lượng phát lại LDAC Codec A2DP Bluetooth ưu tiên"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Hiển thị tùy chọn chứng nhận hiển thị không dây"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Tăng mức ghi nhật ký Wi‑Fi, hiển thị mỗi SSID RSSI trong bộ chọn Wi‑Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Khi được bật, Wi‑Fi sẽ tích cực hơn trong việc chuyển vùng kết nối dữ liệu sang mạng di động khi tín hiệu Wi‑Fi yếu"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 0ef095d..5ec63b3 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"仅使用 HDCP 检查 DRM 内容"</item>
     <item msgid="45075631231212732">"始终使用 HDCP 检查"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"默认"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"默认"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"默认"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"默认"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"默认"</item>
-    <item msgid="5618929009984956469">"16 位/样本"</item>
-    <item msgid="3412640499234627248">"24 位/样本"</item>
-    <item msgid="121583001492929387">"32 位/样本"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"默认"</item>
-    <item msgid="4726688794884191540">"16 位/样本"</item>
-    <item msgid="305344756485516870">"24 位/样本"</item>
-    <item msgid="244568657919675099">"32 位/样本"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"默认"</item>
-    <item msgid="4106832974775067314">"单声道"</item>
-    <item msgid="5571632958424639155">"立体声"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"默认"</item>
-    <item msgid="8900559293912978337">"单声道"</item>
-    <item msgid="8883739882299884241">"立体声"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"音质优先 (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"标准 (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"连接优先 (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"音质优先 (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"标准 (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"连接优先 (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"关闭"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 35a1dfc..3ab17fb 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"始终开启移动数据网络"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用绝对音量功能"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"蓝牙音频编解码器"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"选择首选的蓝牙 A2DP 编解码器"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"蓝牙音频采样率"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"选择首选的蓝牙 A2DP 编解码器采样率"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"蓝牙音频每样本位数"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"选择首选的蓝牙 A2DP 编解码器每样本位数"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"蓝牙音频声道模式"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"选择首选的蓝牙 A2DP 编解码器声道模式"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"蓝牙音频 LDAC 播放质量"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"选择首选的蓝牙 A2DP 编解码器 LDAC 播放质量"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"显示无线显示认证选项"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"提升WLAN日志记录级别(在WLAN选择器中显示每个SSID的RSSI)"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"开启此设置后,系统会在WLAN信号较弱时,主动将网络模式从WLAN网络切换到移动数据网络"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index 872e7c9..953c8cc 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"僅使用 HDCP 檢查 DRM 內容"</item>
     <item msgid="45075631231212732">"永遠使用 HDCP 檢查"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"預設"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"預設"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"預設"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"預設"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"預設"</item>
-    <item msgid="5618929009984956469">"每個樣本 16 位元"</item>
-    <item msgid="3412640499234627248">"每個樣本 24 位元"</item>
-    <item msgid="121583001492929387">"每個樣本 32 位元"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"預設"</item>
-    <item msgid="4726688794884191540">"每個樣本 16 位元"</item>
-    <item msgid="305344756485516870">"每個樣本 24 位元"</item>
-    <item msgid="244568657919675099">"每個樣本 32 位元"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"預設"</item>
-    <item msgid="4106832974775067314">"單聲道"</item>
-    <item msgid="5571632958424639155">"立體聲"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"預設"</item>
-    <item msgid="8900559293912978337">"單聲道"</item>
-    <item msgid="8883739882299884241">"立體聲"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"音質優先 (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"標準 (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"連線優先 (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"音質優先 (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"標準 (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"連線優先 (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"關閉"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 3c5c328..79fc760 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"經常啟用流動數據"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"藍牙音訊編解碼器"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"選取偏好的藍牙 A2DP 編解碼器"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"藍牙音訊取樣率"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"選取偏好的藍牙 A2DP 編解碼器取樣率"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"藍牙音訊每個樣本位元數"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"選取偏好的藍牙 A2DP 編解碼器每個樣本位元數"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"藍牙音訊聲道模式"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"選取偏好的藍牙 A2DP 編解碼器聲道模式"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"藍牙音訊 LDAC 播放音質"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"選取偏好的藍牙 A2DP 編解碼器 LDAC 播放音質"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"啟用時,Wi-Fi 連線會在訊號不穩的情況下更積極轉換成流動數據連線"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index ad99128..d426b30 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"僅使用 HDCP 檢查 DRM 內容"</item>
     <item msgid="45075631231212732">"一律使用 HDCP 檢查"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"預設"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"預設"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"預設"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"預設"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"預設"</item>
-    <item msgid="5618929009984956469">"16 位元/樣本"</item>
-    <item msgid="3412640499234627248">"24 位元/樣本"</item>
-    <item msgid="121583001492929387">"32 位元/樣本"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"預設"</item>
-    <item msgid="4726688794884191540">"16 位元/樣本"</item>
-    <item msgid="305344756485516870">"24 位元/樣本"</item>
-    <item msgid="244568657919675099">"32 位元/樣本"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"預設"</item>
-    <item msgid="4106832974775067314">"單聲道"</item>
-    <item msgid="5571632958424639155">"立體聲"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"預設"</item>
-    <item msgid="8900559293912978337">"單聲道"</item>
-    <item msgid="8883739882299884241">"立體聲"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"音質優先 (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"標準 (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"連線優先 (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"音質優先 (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"標準 (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"連線優先 (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"關閉"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 861834b..2a32252 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"行動數據連線一律保持啟用狀態"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"藍牙音訊轉碼器"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"選取偏好的藍牙 A2DP 轉碼器"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"藍牙音訊取樣率"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"選取偏好的藍牙 A2DP 轉碼器取樣率"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"藍牙音訊每單位樣本位元數"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"選取偏好的藍牙 A2DP 轉碼器每單位樣本位元數"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"藍牙音訊聲道模式"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"選取偏好的藍牙 A2DP 轉碼器聲道模式"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"藍牙音訊 LDAC 播放品質"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"選取偏好的藍牙 A2DP 轉碼器 LDAC 播放品質"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"顯示無線螢幕分享認證的選項"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"讓 Wi‑Fi 記錄功能升級,在 Wi‑Fi 選擇器中依每個 SSID RSSI 顯示 Wi‑Fi 詳細紀錄"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"啟用時,Wi-Fi 連線在訊號不穩的情況下會更積極轉換成行動數據連線"</string>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index 50c1274..04e7614 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -58,66 +58,22 @@
     <item msgid="3878793616631049349">"Sebenzisa ukuhlola kwe-HDCP kokuqukethwe i-DRM kuphela"</item>
     <item msgid="45075631231212732">"Sebenzisa njalo ukuhlola kwe-HDPC"</item>
   </string-array>
-  <string-array name="bluetooth_a2dp_codec_titles">
-    <item msgid="1852387125374225729">"Okuzenzakalelayo"</item>
-    <item msgid="7539690996561263909">"SBC"</item>
-    <item msgid="4260844283202960798">"aptX"</item>
-    <item msgid="7279983368484312990">"aptX-HD"</item>
-    <item msgid="2301339338870319651">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_summaries">
-    <item msgid="9072025520360316957">"Okuzenzakalelayo"</item>
-    <item msgid="6898329690939802290">"SBC"</item>
-    <item msgid="1190434429082395888">"aptX"</item>
-    <item msgid="649699003004233053">"aptX-HD"</item>
-    <item msgid="508106435710925399">"LDAC"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-    <item msgid="7102940318360468759">"Okuzenzakalelayo"</item>
-    <item msgid="8895532488906185219">"44.1 kHz"</item>
-    <item msgid="2909915718994807056">"48.0 kHz"</item>
-    <item msgid="3347287377354164611">"88.2 kHz"</item>
-    <item msgid="1234212100239985373">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
-    <item msgid="7224433008148687313">"Okuzenzakalelayo"</item>
-    <item msgid="4482862757811638365">"44.1 kHz"</item>
-    <item msgid="354495328188724404">"48.0 kHz"</item>
-    <item msgid="7329816882213695083">"88.2 kHz"</item>
-    <item msgid="6967397666254430476">"96.0 kHz"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="6694044160540313386">"Okuzenzakalelayo"</item>
-    <item msgid="5618929009984956469">"16 bits/isampula"</item>
-    <item msgid="3412640499234627248">"24 bits/isampula"</item>
-    <item msgid="121583001492929387">"32 bits/isampula"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="5091076677792306320">"Okuzenzakalelayo"</item>
-    <item msgid="4726688794884191540">"16 bits/isampula"</item>
-    <item msgid="305344756485516870">"24 bits/isampula"</item>
-    <item msgid="244568657919675099">"32 bits/isampula"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-    <item msgid="13423709606339855">"Okuzenzakalelayo"</item>
-    <item msgid="4106832974775067314">"Okukodwa"</item>
-    <item msgid="5571632958424639155">"I-Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="8128478683963250130">"Okuzenzakalelayo"</item>
-    <item msgid="8900559293912978337">"Okukodwa"</item>
-    <item msgid="8883739882299884241">"I-Stereo"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Ikhwalithi yomsindo ekhethwayo (990kbps/909kbps)"</item>
-    <item msgid="138837449700903545">"Okujwayelekile (660kbps/606kbps)"</item>
-    <item msgid="4777177307869441982">"Uxhumo olukhethwayo (330kbps/303kbps)"</item>
-  </string-array>
-  <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Ikhwalithi yomsindo ekhethwayo (990kbps/909kbps)"</item>
-    <item msgid="9091111147684472529">"Okujwayelekile (660kbps/606kbps)"</item>
-    <item msgid="3367904477834831032">"Uxhumo olukhethwayo (330kbps/303kbps)"</item>
-  </string-array>
+    <!-- no translation found for bluetooth_a2dp_codec_titles:0 (7065842274271279580) -->
+    <!-- no translation found for bluetooth_a2dp_codec_titles:3 (500463122137421129) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:0 (5062108632402595000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (3093550793512117000) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_titles:0 (3093023430402746802) -->
+    <!-- no translation found for bluetooth_a2dp_codec_sample_rate_summaries:0 (3214516120190965356) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_titles:0 (2684127272582591429) -->
+    <!-- no translation found for bluetooth_a2dp_codec_bits_per_sample_summaries:0 (1081159789834584363) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_titles:0 (5226878858503393706) -->
+    <!-- no translation found for bluetooth_a2dp_codec_channel_mode_summaries:0 (4118561796005528173) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:0 (3411577996960199959) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:1 (2921767058740704969) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_titles:2 (3682554248829489641) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:0 (7668834469173465015) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:1 (4327143584633311908) -->
+    <!-- no translation found for bluetooth_a2dp_codec_ldac_playback_quality_summaries:2 (6155648878105378550) -->
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Valiwe"</item>
     <item msgid="1593289376502312923">"64K"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 289f4f6..143d4d1 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -171,15 +171,23 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Idatha yeselula ihlala isebenza"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Khubaza ivolumu ngokuphelele"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"I-Bluetooth Audio Codec"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Khetha i-Bluetooth A2DP Codec ethandwayo"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_type_dialog_title (4558347981670553665) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Isilinganiso sesampula yomsindo we-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Khetha isilinganiso sesampuli ye-Bluetooth A2DP Codec ethandwayo"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_sample_rate_dialog_title (5628790207448471613) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Ama-Bits omsindo we-Bluetooth ngesampula ngayinye"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Khetha i-Bluetooth A2DP Codec Bits ethandwayo ngesampula ngayinye"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_bits_per_sample_dialog_title (4546131401358681321) -->
+    <skip />
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Imodi yesiteshi somsindo we-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Khetha imodi yesiteshi se-Bluetooth A2DP Codec ethandwayo"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Ikhwalithi yokudlala ye-LDAC yomsindo we-Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Khetha ikhwalithi yokudlala ye-Bluetooth A2DP Codec LDAC ethandwayo"</string>
+    <!-- no translation found for bluetooth_select_a2dp_codec_channel_mode_dialog_title (9133545781346216071) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality (3619694372407843405) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title (3181967377574368400) -->
+    <skip />
+    <!-- no translation found for bluetooth_select_a2dp_codec_streaming_label (5347862512596240506) -->
+    <skip />
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Bonisa izinketho zokunikeza isitifiketi ukubukeka okungenantambo"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"khuphula izinga lokungena le-Wi-Fi, bonisa nge-SSID RSSI engayodwana kusikhethi se-Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Uma inikwe amandla, i-Wi-Fi izoba namandla kakhulu ekunikezeleni ukuxhumeka kwedatha kuselula, uma isiginali ye-Wi-Fi iphansi"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 5c00985..cfb990e 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -105,10 +105,10 @@
 
     <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>SBC</item>
         <item>aptX</item>
-        <item>aptX-HD</item>
+        <item>aptX HD</item>
         <item>LDAC</item>
     </string-array>
 
@@ -123,16 +123,16 @@
 
     <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>SBC</item>
         <item>aptX</item>
-        <item>aptX-HD</item>
+        <item>aptX HD</item>
         <item>LDAC</item>
     </string-array>
 
     <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>44.1 kHz</item>
         <item>48.0 kHz</item>
         <item>88.2 kHz</item>
@@ -150,7 +150,7 @@
 
     <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>44.1 kHz</item>
         <item>48.0 kHz</item>
         <item>88.2 kHz</item>
@@ -159,7 +159,7 @@
 
     <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>16 bits/sample</item>
         <item>24 bits/sample</item>
         <item>32 bits/sample</item>
@@ -175,7 +175,7 @@
 
     <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>16 bits/sample</item>
         <item>24 bits/sample</item>
         <item>32 bits/sample</item>
@@ -183,7 +183,7 @@
 
     <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>Mono</item>
         <item>Stereo</item>
     </string-array>
@@ -197,16 +197,16 @@
 
     <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>Mono</item>
         <item>Stereo</item>
     </string-array>
 
-    <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40] -->
+    <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70] -->
     <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-        <item>Sound quality preferred (990kbps/909kbps)</item>
-        <item>Standard (660kbps/606kbps)</item>
-        <item>Connection preferred (330kbps/303kbps)</item>
+        <item>Optimize for Audio Quality (990kbps/909kbps)</item>
+        <item>Balanced Audio And Connection Quality (660kbps/606kbps)</item>
+        <item>Optimize for Connection Quality (330kbps/303kbps)</item>
     </string-array>
 
     <!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
@@ -216,11 +216,11 @@
         <item>1002</item>
     </string-array>
 
-    <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40]-->
+    <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70]-->
     <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
-        <item>Sound quality preferred (990kbps/909kbps)</item>
-        <item>Standard (660kbps/606kbps)</item>
-        <item>Connection preferred (330kbps/303kbps)</item>
+        <item>Optimize for Audio Quality</item>
+        <item>Balanced Audio And Connection Quality</item>
+        <item>Optimize for Connection Quality</item>
     </string-array>
 
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index f064e4e..1f35d3e 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -36,7 +36,12 @@
     <declare-styleable name="WifiEncryptionState">
         <attr name="state_encrypted" format="boolean" />
     </declare-styleable>
+    <declare-styleable name="WifiSavedState">
+        <attr name="state_saved" format="boolean" />
+    </declare-styleable>
+
     <attr name="wifi_signal" format="reference" />
+    <attr name="wifi_friction" format="reference" />
 
     <declare-styleable name="UsageView">
         <attr name="android:colorAccent" />
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 93bd5dc..a1b2bdf 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -430,28 +430,31 @@
 
     <!-- UI debug setting: Select Bluetooth Audio Codec -->
     <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec -->
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Preferred Bluetooth A2DP Codec</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec -->
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Bluetooth Audio Codec</string>
 
     <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
     <string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Sample Rate -->
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Preferred Bluetooth A2DP Codec Sample Rate</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec: Sample Rate -->
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Bluetooth Audio Codec:\u000ASample Rate</string>
 
     <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
     <string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Bits Per Sample -->
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Preferred Bluetooth A2DP Codec Bits Per Sample</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec: Bits Per Sample -->
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Bluetooth Audio Codec:\u000ABits Per Sample</string>
 
     <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
     <string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Channel Mode -->
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Preferred Bluetooth A2DP Codec Channel Mode</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec: Channel Mode -->
+    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Bluetooth Audio Codec:\u000AChannel Mode</string>
 
     <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Playback Quality</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec LDAC Playback Quality -->
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Preferred Bluetooth A2DP Codec LDAC Playback Quality</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Codec: Playback Quality</string>
+    <!-- UI debug setting: Select Bluetooth Audio LDAC Codec: LDAC Playback Quality -->
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Bluetooth Audio LDAC Codec:\u000APlayback Quality</string>
+
+    <!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
+    <string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
 
     <!-- setting Checkbox summary whether to show options for wireless display certification  -->
     <string name="wifi_display_certification_summary">Show options for wireless display certification</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 6179244..fbc6aa3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -13,8 +13,11 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.net.ConnectivityManager;
+import android.net.ScoredNetwork;
 import android.os.BatteryManager;
 import android.os.UserManager;
 import android.print.PrintManager;
@@ -29,6 +32,14 @@
     private static String sServicesSystemSharedLibPackageName;
     private static String sSharedSystemSharedLibPackageName;
 
+    static final int[] WIFI_PIE_FOR_BADGING = {
+          com.android.internal.R.drawable.ic_signal_wifi_badged_0_bars,
+          com.android.internal.R.drawable.ic_signal_wifi_badged_1_bar,
+          com.android.internal.R.drawable.ic_signal_wifi_badged_2_bars,
+          com.android.internal.R.drawable.ic_signal_wifi_badged_3_bars,
+          com.android.internal.R.drawable.ic_signal_wifi_badged_4_bars
+    };
+
     /**
      * Return string resource that best describes combination of tethering
      * options available on this device.
@@ -160,10 +171,7 @@
 
     @ColorInt
     public static int getColorAccent(Context context) {
-        TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
-        @ColorInt int colorAccent = ta.getColor(0, 0);
-        ta.recycle();
-        return colorAccent;
+        return getColorAttr(context, android.R.attr.colorAccent);
     }
 
     @ColorInt
@@ -182,6 +190,29 @@
         return list.getDefaultColor();
     }
 
+    @ColorInt
+    public static int getDisabled(Context context, int inputColor) {
+        return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
+    }
+
+    @ColorInt
+    public static int applyAlphaAttr(Context context, int attr, int inputColor) {
+        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+        float alpha = ta.getFloat(0, 0);
+        ta.recycle();
+        alpha *= Color.alpha(inputColor);
+        return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
+                Color.blue(inputColor));
+    }
+
+    @ColorInt
+    public static int getColorAttr(Context context, int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+        @ColorInt int colorAccent = ta.getColor(0, 0);
+        ta.recycle();
+        return colorAccent;
+    }
+
     /**
      * Determine whether a package is a "system package", in which case certain things (like
      * disabling notifications or disabling the package altogether) should be disallowed.
@@ -233,4 +264,41 @@
                 com.android.internal.R.string.config_deviceProvisioningPackage);
         return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
     }
+
+    /**
+     * Returns a badged Wifi icon drawable.
+     *
+     * <p>The first layer contains the Wifi pie and the second layer contains the badge. Callers
+     * should set the drawable to the appropriate size and tint color.
+     *
+     * @param context The caller's context (must have access to internal resources)
+     * @param level The number of bars to show (0-4)
+     * @param badge The badge enum {@see android.net.ScoredNetwork}
+     *
+     * @throws IllegalArgumentException if an invalid badge enum is given
+     *
+     * @deprecated TODO(sghuman): Finalize the form of this method and then move it to a new
+     *         location.
+     */
+    public static LayerDrawable getBadgedWifiIcon(Context context, int level, int badge) {
+        return new LayerDrawable(
+                new Drawable[] {
+                        context.getDrawable(WIFI_PIE_FOR_BADGING[level]),
+                        context.getDrawable(getWifiBadgeResource(badge))
+                });
+    }
+
+    private static int getWifiBadgeResource(int badge) {
+        switch (badge) {
+            case ScoredNetwork.BADGING_SD:
+                return com.android.internal.R.drawable.ic_signal_wifi_badged_sd;
+            case ScoredNetwork.BADGING_HD:
+                return com.android.internal.R.drawable.ic_signal_wifi_badged_hd;
+            case ScoredNetwork.BADGING_4K:
+                return com.android.internal.R.drawable.ic_signal_wifi_badged_4k;
+            default:
+                throw new IllegalArgumentException(
+                    "No badge resource found for badge value: " + badge);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index fcff305..9bb3c36 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -28,6 +28,8 @@
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.internal.R;
+
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -147,6 +149,26 @@
                 enabledServicesBuilder.toString(), userId);
     }
 
+    /**
+     * Get the name of the service that should be toggled by the accessibility shortcut. Use
+     * an OEM-configurable default if the setting has never been set.
+     *
+     * @param context A valid context
+     * @param userId The user whose settings should be checked
+     *
+     * @return The component name, flattened to a string, of the target service.
+     */
+    public static String getShortcutTargetServiceComponentNameString(
+            Context context, int userId) {
+        final String currentShortcutServiceId = Settings.Secure.getStringForUser(
+                context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                userId);
+        if (currentShortcutServiceId != null) {
+            return currentShortcutServiceId;
+        }
+        return context.getString(R.string.config_defaultAccessibilityService);
+    }
+
     private static Set<ComponentName> getInstalledServices(Context context) {
         final Set<ComponentName> installedServices = new HashSet<>();
         installedServices.clear();
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index d34dd89..d4623d6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -22,13 +22,22 @@
 
 public class InterestingConfigChanges {
     private final Configuration mLastConfiguration = new Configuration();
+    private final int mFlags;
     private int mLastDensity;
 
+    public InterestingConfigChanges() {
+        this(0);
+    }
+
+    public InterestingConfigChanges(int extraFlags) {
+        mFlags = extraFlags | ActivityInfo.CONFIG_LOCALE
+                | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT;
+    }
+
     public boolean applyNewConfig(Resources res) {
         int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
         boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
-        if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE
-                |ActivityInfo.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0) {
+        if (densityChanged || (configChanges & (mFlags)) != 0) {
             mLastDensity = res.getDisplayMetrics().densityDpi;
             return true;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index b327be0..6e10aab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
@@ -105,6 +106,12 @@
     private static final String EXTRA_CATEGORY_KEY = "com.android.settings.category";
 
     /**
+     * The key used to get the package name of the icon resource for the preference.
+     */
+    private static final String EXTRA_PREFERENCE_ICON_PACKAGE =
+        "com.android.settings.icon_package";
+
+    /**
      * Name of the meta-data item that should be set in the AndroidManifest.xml
      * to specify the key that should be used for the preference.
      */
@@ -342,6 +349,7 @@
             ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) {
         if (applicationInfo.isSystemApp()) {
             int icon = 0;
+            Pair<String, Integer> iconFromUri = null;
             CharSequence title = null;
             String summary = null;
             String keyHint = null;
@@ -358,10 +366,10 @@
 
                 if (res != null && metaData != null) {
                     if (metaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
-                        icon = getIconFromUri(context,
+                        iconFromUri = getIconFromUri(context, activityInfo.packageName,
                                 metaData.getString(META_DATA_PREFERENCE_ICON_URI), providerMap);
                     }
-                    if ((icon == 0) && metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
+                    if (iconFromUri == null && metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
                         icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
                     }
                     if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
@@ -401,12 +409,18 @@
             if (TextUtils.isEmpty(title)) {
                 title = activityInfo.loadLabel(pm).toString();
             }
-            if (icon == 0) {
-                icon = activityInfo.icon;
+
+            // Set the icon
+            if (iconFromUri != null) {
+                tile.icon = Icon.createWithResource(iconFromUri.first, iconFromUri.second);
+            } else {
+                if (icon == 0) {
+                    icon = activityInfo.icon;
+                }
+                tile.icon = Icon.createWithResource(activityInfo.packageName, icon);
             }
 
-            // Set icon, title and summary for the preference
-            tile.icon = Icon.createWithResource(activityInfo.packageName, icon);
+            // Set title and summary for the preference
             tile.title = title;
             tile.summary = summary;
             // Replace the intent with this specific activity
@@ -422,16 +436,33 @@
     }
 
     /**
-     * Gets the icon resource id from content provider.
+     * Gets the icon package name and resource id from content provider.
      * @param Context context
+     * @param packageName package name of the target activity
      * @param uriString URI for the content provider
      * @param providerMap Maps URI authorities to providers
-     * @return Resource id if returned by the content provider, otherwise 0
+     * @return package name and resource id of the icon specified
      */
-    public static int getIconFromUri(Context context, String uriString,
-            Map<String, IContentProvider> providerMap) {
+    public static Pair<String, Integer> getIconFromUri(Context context, String packageName,
+            String uriString, Map<String, IContentProvider> providerMap) {
         Bundle bundle = getBundleFromUri(context, uriString, providerMap);
-        return (bundle != null) ? bundle.getInt(META_DATA_PREFERENCE_ICON, 0) : 0;
+        if (bundle == null) {
+            return null;
+        }
+        String iconPackageName = bundle.getString(EXTRA_PREFERENCE_ICON_PACKAGE);
+        if (TextUtils.isEmpty(iconPackageName)) {
+            return null;
+        }
+        int resId = bundle.getInt(META_DATA_PREFERENCE_ICON, 0);
+        if (resId == 0) {
+            return null;
+        }
+        // Icon can either come from the target package or from the Settings app.
+        if (iconPackageName.equals(packageName)
+                || iconPackageName.equals(context.getPackageName())) {
+            return Pair.create(iconPackageName, bundle.getInt(META_DATA_PREFERENCE_ICON, 0));
+        }
+        return null;
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index e7450fa..06ea445 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -27,12 +27,15 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
+import android.net.NetworkKey;
+import android.net.ScoredNetwork;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkScoreCache;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -48,6 +51,7 @@
 import com.android.settingslib.R;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -132,6 +136,9 @@
 
     private Object mTag;
 
+    private int mRankingScore = Integer.MIN_VALUE;
+    private int mBadge = ScoredNetwork.BADGING_NONE;
+
     // used to co-relate internal vs returned accesspoint.
     int mId;
 
@@ -205,6 +212,8 @@
         this.mScanResultCache.clear();
         this.mScanResultCache.putAll(that.mScanResultCache);
         this.mId = that.mId;
+        this.mBadge = that.mBadge;
+        this.mRankingScore = that.mRankingScore;
     }
 
     @Override
@@ -213,6 +222,11 @@
         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;
@@ -268,9 +282,38 @@
         if (security != SECURITY_NONE) {
             builder.append(',').append(securityToString(security, pskType));
         }
+        builder.append(",rankingScore=").append(mRankingScore);
+        builder.append(",badge=").append(mBadge);
+
         return builder.append(')').toString();
     }
 
+    /**
+     * Updates the AccessPoint rankingScore and badge, returning true if the data has changed.
+     *
+     * @param scoreCache The score cache to use to retrieve scores.
+     */
+    boolean updateScores(WifiNetworkScoreCache scoreCache) {
+        int oldBadge = mBadge;
+        int oldRankingScore = mRankingScore;
+        mBadge = ScoredNetwork.BADGING_NONE;
+        mRankingScore = Integer.MIN_VALUE;
+
+        for (ScanResult result : mScanResultCache.values()) {
+            ScoredNetwork score = scoreCache.getScoredNetwork(result);
+            if (score == null) {
+                continue;
+            }
+
+            if (score.hasRankingScore()) {
+                mRankingScore = Math.max(mRankingScore, score.calculateRankingScore(result.level));
+            }
+            mBadge = Math.max(mBadge, score.calculateBadge(result.level));
+        }
+
+        return (oldBadge != mBadge || oldRankingScore != mRankingScore);
+    }
+
     private void evictOldScanResults() {
         long nowMs = SystemClock.elapsedRealtime();
         for (Iterator<ScanResult> iter = mScanResultCache.values().iterator(); iter.hasNext(); ) {
@@ -555,6 +598,8 @@
             visibility.append(" rssi=").append(mInfo.getRssi());
             visibility.append(" ");
             visibility.append(" score=").append(mInfo.score);
+            visibility.append(" rankingScore=").append(getRankingScore());
+            visibility.append(" badge=").append(getBadge());
             visibility.append(String.format(" tx=%.1f,", mInfo.txSuccessRate));
             visibility.append(String.format("%.1f,", mInfo.txRetriesRate));
             visibility.append(String.format("%.1f ", mInfo.txBadRate));
@@ -820,6 +865,14 @@
         mRssi = rssi;
     }
 
+    int getRankingScore() {
+        return mRankingScore;
+    }
+
+    int getBadge() {
+        return mBadge;
+    }
+
     public static String getSummary(Context context, String ssid, DetailedState state,
             boolean isEphemeral, String passpointProvider) {
         if (state == DetailedState.CONNECTED && ssid == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index aae9cf6..8ebea61 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -18,8 +18,12 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.StateListDrawable;
+import android.net.ScoredNetwork;
 import android.net.wifi.WifiConfiguration;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -28,19 +32,27 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.SparseArray;
+import android.widget.ImageView;
 import android.widget.TextView;
 import com.android.settingslib.R;
+import com.android.settingslib.Utils;
 
 public class AccessPointPreference extends Preference {
 
     private static final int[] STATE_SECURED = {
             R.attr.state_encrypted
     };
+    private static final int[] STATE_SAVED = {
+            R.attr.state_encrypted,
+            R.attr.state_saved
+    };
     private static final int[] STATE_NONE = {};
 
-    private static int[] wifi_signal_attributes = { R.attr.wifi_signal };
+    private static final int[] wifi_signal_attributes = { R.attr.wifi_signal };
+    private static final int[] wifi_friction_attributes = { R.attr.wifi_friction };
 
     private final StateListDrawable mWifiSld;
+    private final StateListDrawable mFrictionSld;
     private final int mBadgePadding;
     private final UserBadgeCache mBadgeCache;
     private TextView mTitleView;
@@ -51,6 +63,9 @@
     private int mLevel;
     private CharSequence mContentDescription;
     private int mDefaultIconResId;
+    private int mIconWidth;
+    private int mIconHeight;
+    private int mWifiBadge = ScoredNetwork.BADGING_NONE;
 
     static final int[] WIFI_CONNECTION_STRENGTH = {
             R.string.accessibility_wifi_one_bar,
@@ -63,6 +78,7 @@
     public AccessPointPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         mWifiSld = null;
+        mFrictionSld = null;
         mBadgePadding = 0;
         mBadgeCache = null;
     }
@@ -70,6 +86,7 @@
     public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
             boolean forSavedNetworks) {
         super(context);
+        setWidgetLayoutResource(R.layout.access_point_friction_widget);
         mBadgeCache = cache;
         mAccessPoint = accessPoint;
         mForSavedNetworks = forSavedNetworks;
@@ -78,6 +95,17 @@
 
         mWifiSld = (StateListDrawable) context.getTheme()
                 .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+        // Save icon width and height to use for creating a badged icon
+        setIconWidthAndHeight();
+
+        TypedArray frictionSld;
+        try {
+            frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
+        } catch (Resources.NotFoundException e) {
+            // Fallback for platforms that do not need friction icon resources.
+            frictionSld = null;
+        }
+        mFrictionSld = frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
 
         // Distance from the end of the title at which this AP's user badge should sit.
         mBadgePadding = context.getResources()
@@ -88,6 +116,7 @@
     public AccessPointPreference(AccessPoint accessPoint, Context context, UserBadgeCache cache,
             int iconResId, boolean forSavedNetworks) {
         super(context);
+        setWidgetLayoutResource(R.layout.access_point_friction_widget);
         mBadgeCache = cache;
         mAccessPoint = accessPoint;
         mForSavedNetworks = forSavedNetworks;
@@ -97,12 +126,30 @@
 
         mWifiSld = (StateListDrawable) context.getTheme()
                 .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
+        // Save icon width and height to use for creating a badged icon
+        setIconWidthAndHeight();
+
+        TypedArray frictionSld;
+        try {
+            frictionSld = context.getTheme().obtainStyledAttributes(wifi_friction_attributes);
+        } catch (Resources.NotFoundException e) {
+            // Fallback for platforms that do not need friction icon resources.
+            frictionSld = null;
+        }
+        mFrictionSld = frictionSld != null ? (StateListDrawable) frictionSld.getDrawable(0) : null;
 
         // Distance from the end of the title at which this AP's user badge should sit.
         mBadgePadding = context.getResources()
                 .getDimensionPixelSize(R.dimen.wifi_preference_badge_padding);
     }
 
+    private void setIconWidthAndHeight() {
+        // TODO(sghuman): Refactor this defined widths and heights into a dimension resource and
+        // reference directly.
+        mIconWidth = mWifiSld.getIntrinsicWidth();
+        mIconHeight = mWifiSld.getIntrinsicHeight();
+    }
+
     public AccessPoint getAccessPoint() {
         return mAccessPoint;
     }
@@ -126,12 +173,27 @@
             mTitleView.setCompoundDrawablePadding(mBadgePadding);
         }
         view.itemView.setContentDescription(mContentDescription);
+
+        if (!mForSavedNetworks) {
+            ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
+            bindFrictionImage(frictionImageView);
+        }
     }
 
     protected void updateIcon(int level, Context context) {
         if (level == -1) {
             safeSetDefaultIcon();
         } else {
+           if (mWifiBadge != ScoredNetwork.BADGING_NONE) {
+                // TODO(sghuman): Refactor this to reuse drawable to save memory and add to a
+                // special subclass of AccessPointPreference
+                LayerDrawable drawable = Utils.getBadgedWifiIcon(context, level, mWifiBadge);
+                drawable.setLayerSize(0, mIconWidth, mIconHeight);
+                drawable.setLayerSize(1, mIconWidth, mIconHeight);
+                drawable.setTint(Utils.getColorAccent(getContext()));
+                setIcon(drawable);
+                return;
+            }
             if (getIcon() == null) {
                 // To avoid a drawing race condition, we first set the state (SECURE/NONE) and then
                 // set the icon (drawable) to that state's drawable.
@@ -152,6 +214,27 @@
         }
     }
 
+    /**
+     * Binds the friction icon drawable using a StateListDrawable.
+     *
+     * <p>Friction icons will be rebound when notifyChange() is called, and therefore
+     * do not need to be managed in refresh()</p>.
+     */
+    private void bindFrictionImage(ImageView frictionImageView) {
+        if (frictionImageView == null || mFrictionSld == null) {
+            return;
+        }
+        if (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE) {
+            if (mAccessPoint.isSaved()) {
+                mFrictionSld.setState(STATE_SAVED);
+            } else {
+                mFrictionSld.setState(STATE_SECURED);
+            }
+        }
+        Drawable drawable = mFrictionSld.getCurrent();
+        frictionImageView.setImageDrawable(drawable);
+    }
+
     private void safeSetDefaultIcon() {
         if (mDefaultIconResId != 0) {
             setIcon(mDefaultIconResId);
@@ -182,11 +265,14 @@
 
         final Context context = getContext();
         int level = mAccessPoint.getLevel();
-        if (level != mLevel) {
+        int wifiBadge = mAccessPoint.getBadge();
+        if (level != mLevel || wifiBadge != mWifiBadge) {
             mLevel = level;
+            mWifiBadge = wifiBadge;
             updateIcon(mLevel, context);
             notifyChanged();
         }
+
         updateBadge(context);
 
         setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 77a45b3..799f388 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -24,15 +24,22 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkKey;
 import android.net.NetworkRequest;
+import android.net.NetworkScoreManager;
+import android.net.ScoredNetwork;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkScoreCache;
+import android.net.wifi.WifiNetworkScoreCache.CacheListener;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.support.annotation.WorkerThread;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -49,14 +56,18 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Tracks saved or available wifi networks and their state.
  */
 public class WifiTracker {
+    // TODO(sghuman): Document remaining methods with @UiThread and @WorkerThread where possible.
+    // TODO(sghuman): Refactor to avoid calling certain methods on the UiThread.
+
     private static final String TAG = "WifiTracker";
-    private static final boolean DBG = false;
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
     /** verbose logging flag. this flag is set thru developer debugging options
      * and used so as to assist with in-the-field WiFi connectivity debugging  */
@@ -122,6 +133,10 @@
     private NetworkInfo mLastNetworkInfo;
     private WifiInfo mLastInfo;
 
+    private final NetworkScoreManager mNetworkScoreManager;
+    private final WifiNetworkScoreCache mScoreCache;
+    private final Set<NetworkKey> mRequestedScores = new ArraySet<>();
+
     @VisibleForTesting
     Scanner mScanner;
 
@@ -144,14 +159,16 @@
             boolean includeSaved, boolean includeScans, boolean includePasspoints) {
         this(context, wifiListener, workerLooper, includeSaved, includeScans, includePasspoints,
                 context.getSystemService(WifiManager.class),
-                context.getSystemService(ConnectivityManager.class), Looper.myLooper());
+                context.getSystemService(ConnectivityManager.class),
+                context.getSystemService(NetworkScoreManager.class), Looper.myLooper()
+        );
     }
 
     @VisibleForTesting
     WifiTracker(Context context, WifiListener wifiListener, Looper workerLooper,
             boolean includeSaved, boolean includeScans, boolean includePasspoints,
             WifiManager wifiManager, ConnectivityManager connectivityManager,
-            Looper currentLooper) {
+            NetworkScoreManager networkScoreManager, Looper currentLooper) {
         if (!includeSaved && !includeScans) {
             throw new IllegalArgumentException("Must include either saved or scans");
         }
@@ -186,6 +203,18 @@
                 .clearCapabilities()
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                 .build();
+
+        mNetworkScoreManager = networkScoreManager;
+
+        mScoreCache = new WifiNetworkScoreCache(context, new CacheListener(mWorkHandler) {
+            @Override
+            public void networkCacheUpdated(List<ScoredNetwork> networks) {
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "Score cache was updated with networks: " + networks);
+                }
+                Message.obtain(mWorkHandler, WorkHandler.MSG_UPDATE_NETWORK_SCORES).sendToTarget();
+            }
+        });
     }
 
     /**
@@ -216,6 +245,8 @@
 
     /**
      * Resume scanning for wifi networks after it has been paused.
+     *
+     * <p>The score cache should be registered before this method is invoked.
      */
     public void resumeScanning() {
         if (mScanner == null) {
@@ -230,11 +261,20 @@
     }
 
     /**
-     * Start tracking wifi networks.
-     * Registers listeners and starts scanning for wifi networks. If this is not called
+     * Start tracking wifi networks and scores.
+     *
+     * <p>Registers listeners and starts scanning for wifi networks. If this is not called
      * then forceUpdate() must be called to populate getAccessPoints().
      */
     public void startTracking() {
+        mWorkHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                registerScoreCache();
+            }
+        });
+
+
         resumeScanning();
         if (!mRegistered) {
             mContext.registerReceiver(mReceiver, mFilter);
@@ -245,9 +285,28 @@
         }
     }
 
+    @WorkerThread
+    private void registerScoreCache() {
+        mNetworkScoreManager.registerNetworkScoreCache(
+                NetworkKey.TYPE_WIFI,
+                mScoreCache,
+                NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
+    }
+
+    private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) {
+        if (keys.isEmpty()) return;
+
+        if (DBG) {
+            Log.d(TAG, "Requesting scores for Network Keys: " + keys);
+        }
+        mNetworkScoreManager.requestScores(keys.toArray(new NetworkKey[keys.size()]));
+        mRequestedScores.addAll(keys);
+    }
+
     /**
-     * Stop tracking wifi networks.
-     * Unregisters all listeners and stops scanning for wifi networks. This should always
+     * Stop tracking wifi networks and scores.
+     *
+     * <p>Unregisters all listeners and stops scanning for wifi networks. This should always
      * be called when done with a WifiTracker (if startTracking was called) to ensure
      * proper cleanup.
      */
@@ -255,11 +314,26 @@
         if (mRegistered) {
             mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_ACCESS_POINTS);
             mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_NETWORK_INFO);
+            mWorkHandler.removeMessages(WorkHandler.MSG_UPDATE_NETWORK_SCORES);
             mContext.unregisterReceiver(mReceiver);
             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
             mRegistered = false;
         }
         pauseScanning();
+
+        mWorkHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                unregisterAndClearScoreCache();
+            }
+        });
+    }
+
+    @WorkerThread
+    private void unregisterAndClearScoreCache() {
+        mRequestedScores.clear();
+        mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, mScoreCache);
+        mScoreCache.clearScores();
     }
 
     /**
@@ -415,6 +489,7 @@
             }
         }
 
+        final List<NetworkKey> scoresToRequest = new ArrayList<>();
         if (results != null) {
             for (ScanResult result : results) {
                 // Ignore hidden and ad-hoc networks.
@@ -423,6 +498,11 @@
                     continue;
                 }
 
+                NetworkKey key = NetworkKey.createFromScanResult(result);
+                if (!mRequestedScores.contains(key)) {
+                    scoresToRequest.add(key);
+                }
+
                 boolean found = false;
                 for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {
                     if (accessPoint.update(result)) {
@@ -457,27 +537,35 @@
             }
         }
 
+
+        requestScoresForNetworkKeys(scoresToRequest);
+        for (AccessPoint ap : accessPoints) {
+            ap.updateScores(mScoreCache);
+        }
+
         // Pre-sort accessPoints to speed preference insertion
         Collections.sort(accessPoints);
 
         // Log accesspoints that were deleted
-        if (DBG) Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
-        for (AccessPoint prevAccessPoint : mInternalAccessPoints) {
-            if (prevAccessPoint.getSsid() == null)
-                continue;
-            String prevSsid = prevAccessPoint.getSsidStr();
-            boolean found = false;
-            for (AccessPoint newAccessPoint : accessPoints) {
-                if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid()
-                        .equals(prevSsid)) {
-                    found = true;
-                    break;
+        if (DBG) {
+            Log.d(TAG, "------ Dumping SSIDs that were not seen on this scan ------");
+            for (AccessPoint prevAccessPoint : mInternalAccessPoints) {
+                if (prevAccessPoint.getSsid() == null)
+                    continue;
+                String prevSsid = prevAccessPoint.getSsidStr();
+                boolean found = false;
+                for (AccessPoint newAccessPoint : accessPoints) {
+                    if (newAccessPoint.getSsid() != null && newAccessPoint.getSsid()
+                            .equals(prevSsid)) {
+                        found = true;
+                        break;
+                    }
                 }
+                if (!found)
+                    Log.d(TAG, "Did not find " + prevSsid + " in this scan");
             }
-            if (!found)
-                if (DBG) Log.d(TAG, "Did not find " + prevSsid + " in this scan");
+            Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");
         }
-        if (DBG) Log.d(TAG, "---- Done dumping SSIDs that were not seen on this scan ----");
 
         mInternalAccessPoints.clear();
         mInternalAccessPoints.addAll(accessPoints);
@@ -549,7 +637,38 @@
 
         boolean reorder = false;
         for (int i = mInternalAccessPoints.size() - 1; i >= 0; --i) {
-            if (mInternalAccessPoints.get(i).update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
+            AccessPoint ap = mInternalAccessPoints.get(i);
+            if (ap.update(connectionConfig, mLastInfo, mLastNetworkInfo)) {
+                reorder = true;
+            }
+            if (ap.updateScores(mScoreCache)) {
+                reorder = true;
+            }
+        }
+        if (reorder) {
+            Collections.sort(mInternalAccessPoints);
+            mMainHandler.scheduleAPCopyingAndCloseWriteLock();
+        }
+    }
+
+    /**
+     * Update all the internal access points rankingScores and badge.
+     *
+     * <p>Will trigger a resort and notify listeners of changes if applicable.
+     */
+    private void updateNetworkScores() {
+        // Lock required to prevent accidental copying of AccessPoint states while the modification
+        // is in progress. see #copyAndNotifyListeners
+        long before = System.currentTimeMillis();
+        mInternalAccessPointsWriteLock.block();
+        if (DBG) {
+            Log.d(TAG, "Acquired AP lock on WorkerHandler for inserting NetworkScores. Wait time = " +
+                    (System.currentTimeMillis() - before) + "ms.");
+        }
+
+        boolean reorder = false;
+        for (int i = 0; i < mInternalAccessPoints.size(); i++) {
+            if (mInternalAccessPoints.get(i).updateScores(mScoreCache)) {
                 reorder = true;
             }
         }
@@ -661,6 +780,7 @@
         private static final int MSG_UPDATE_NETWORK_INFO = 1;
         private static final int MSG_RESUME = 2;
         private static final int MSG_UPDATE_WIFI_STATE = 3;
+        private static final int MSG_UPDATE_NETWORK_SCORES = 4;
 
         public WorkHandler(Looper looper) {
             super(looper);
@@ -695,6 +815,9 @@
                     mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
                             .sendToTarget();
                     break;
+                case MSG_UPDATE_NETWORK_SCORES:
+                    updateNetworkScores();
+                    break;
             }
         }
     }
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 4208522..98bce0c 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -27,7 +27,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
     espresso-core \
-    mockito-target-minus-junit4
+    mockito-target-minus-junit4 \
+    legacy-android-test
 
 include frameworks/base/packages/SettingsLib/common.mk
 
diff --git a/packages/SettingsLib/tests/integ/AndroidManifest.xml b/packages/SettingsLib/tests/integ/AndroidManifest.xml
index 00b2164..0d5ff2c 100644
--- a/packages/SettingsLib/tests/integ/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/integ/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
     <uses-permission android:name="android.permission.SET_TIME_ZONE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
 
     <application>
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 c650190..eaf0367 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
@@ -15,29 +15,278 @@
  */
 package com.android.settingslib.wifi;
 
-
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
+import android.net.ScoredNetwork;
+import android.net.RssiCurve;
+import android.net.WifiKey;
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiNetworkScoreCache;
+import android.net.wifi.WifiSsid;
+import android.os.Bundle;
 import android.os.SystemClock;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.mockito.ArgumentCaptor;
+import org.mockito.Matchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.List;
-
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class WifiTrackerTest {
 
+    private static final String TAG = "WifiTrackerTest";
+    private static final int LATCH_TIMEOUT = 2000;
+
+    private static final String SSID_1 = "ssid1";
+    private static final String BSSID_1 = "00:00:00:00:00:00";
+    private static final NetworkKey NETWORK_KEY_1 =
+            new NetworkKey(new WifiKey('"' + SSID_1 + '"', BSSID_1));
+    private static final int RSSI_1 = -30;
+    private static final byte SCORE_1 = 10;
+    private static final int BADGE_1 = ScoredNetwork.BADGING_SD;
+
+    private static final String SSID_2 = "ssid2";
+    private static final String BSSID_2 = "AA:AA:AA:AA:AA:AA";
+    private static final NetworkKey NETWORK_KEY_2 =
+            new NetworkKey(new WifiKey('"' + SSID_2 + '"', BSSID_2));
+    private static final int RSSI_2 = -30;
+    private static final byte SCORE_2 = 15;
+    private static final int BADGE_2 = ScoredNetwork.BADGING_HD;
+
+    @Captor ArgumentCaptor<WifiNetworkScoreCache> mScoreCacheCaptor;
+    @Mock private ConnectivityManager mockConnectivityManager;
+    @Mock private NetworkScoreManager mockNetworkScoreManager;
+    @Mock private RssiCurve mockCurve1;
+    @Mock private RssiCurve mockCurve2;
+    @Mock private RssiCurve mockBadgeCurve1;
+    @Mock private RssiCurve mockBadgeCurve2;
+    @Mock private WifiManager mockWifiManager;
+    @Mock private WifiTracker.WifiListener mockWifiListener;
+
+    private final List<NetworkKey> mRequestedKeys = new ArrayList<>();
+
+    private Context mContext;
+    private CountDownLatch mAccessPointsChangedLatch;
+    private CountDownLatch mRequestScoresLatch;
+    private Handler mScannerHandler;
+    private HandlerThread mMainThread;
+    private HandlerThread mWorkerThread;
+    private Looper mLooper;
+    private Looper mMainLooper;
+    private int mOriginalSettingValue;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        MockitoAnnotations.initMocks(this);
+
+        mWorkerThread = new HandlerThread("TestHandlerWorkerThread");
+        mWorkerThread.start();
+        mLooper = mWorkerThread.getLooper();
+        mMainThread = new HandlerThread("TestHandlerThread");
+        mMainThread.start();
+        mMainLooper = mMainThread.getLooper();
+
+        // Make sure the scanner doesn't try to run on the testing thread.
+        HandlerThread scannerThread = new HandlerThread("ScannerWorkerThread");
+        scannerThread.start();
+        mScannerHandler = new Handler(scannerThread.getLooper());
+
+        when(mockWifiManager.isWifiEnabled()).thenReturn(true);
+        when(mockWifiManager.getScanResults())
+                .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2()));
+
+
+        when(mockCurve1.lookupScore(RSSI_1)).thenReturn(SCORE_1);
+        when(mockCurve2.lookupScore(RSSI_2)).thenReturn(SCORE_2);
+
+        when(mockBadgeCurve1.lookupScore(RSSI_1)).thenReturn((byte) BADGE_1);
+        when(mockBadgeCurve2.lookupScore(RSSI_2)).thenReturn((byte) BADGE_2);
+
+        doNothing()
+                .when(mockNetworkScoreManager)
+                .registerNetworkScoreCache(
+                        anyInt(),
+                        mScoreCacheCaptor.capture(),
+                        Matchers.anyInt());
+
+        // Capture requested keys and count down latch if present
+        doAnswer(
+                new Answer<Boolean>() {
+                    @Override
+                    public Boolean answer(InvocationOnMock input) {
+                        if (mRequestScoresLatch != null) {
+                            mRequestScoresLatch.countDown();
+                        }
+                        NetworkKey[] keys = (NetworkKey[]) input.getArguments()[0];
+                        for (NetworkKey key : keys) {
+                            mRequestedKeys.add(key);
+                        }
+                        return true;
+                    }
+                }).when(mockNetworkScoreManager).requestScores(Matchers.<NetworkKey[]>any());
+
+        doAnswer(
+                new Answer<Void>() {
+                  @Override
+                  public Void answer (InvocationOnMock invocation) throws Throwable {
+                    if (mAccessPointsChangedLatch != null) {
+                      mAccessPointsChangedLatch.countDown();
+                    }
+
+                    return null;
+                  }
+                }).when(mockWifiListener).onAccessPointsChanged();
+
+        mOriginalSettingValue = Settings.Global.getInt(
+            InstrumentationRegistry.getTargetContext().getContentResolver(),
+            Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+            0 /* disabled */);
+
+    }
+
+    @After
+    public void cleanUp() {
+        Settings.Global.putInt(
+            InstrumentationRegistry.getTargetContext().getContentResolver(),
+            Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+            mOriginalSettingValue);
+    }
+
+    private static ScanResult buildScanResult1() {
+        return new ScanResult(
+                WifiSsid.createFromAsciiEncoded(SSID_1),
+                BSSID_1,
+                0, // hessid
+                0, //anqpDomainId
+                null, // osuProviders
+                "", // capabilities
+                RSSI_1,
+                0, // frequency
+                SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
+    }
+
+    private static ScanResult buildScanResult2() {
+        return new ScanResult(
+                WifiSsid.createFromAsciiEncoded(SSID_2),
+                BSSID_2,
+                0, // hessid
+                0, //anqpDomainId
+                null, // osuProviders
+                "", // capabilities
+                RSSI_2,
+                0, // frequency
+                SystemClock.elapsedRealtime() * 1000 /* microsecond timestamp */);
+    }
+
+    private WifiTracker createTrackerAndInjectInitialScanResults() throws InterruptedException {
+        WifiTracker tracker = createMockedWifiTracker();
+        startTracking(tracker);
+
+        mAccessPointsChangedLatch = new CountDownLatch(1);
+        sendScanResultsAndProcess(tracker);
+        mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+
+        return tracker;
+    }
+
+    private WifiTracker createMockedWifiTracker() {
+        WifiTracker tracker =
+                new WifiTracker(
+                    mContext,
+                    mockWifiListener,
+                    mLooper,
+                    true,
+                    true,
+                    true,
+                    mockWifiManager,
+                    mockConnectivityManager,
+                        mockNetworkScoreManager, mMainLooper
+                );
+
+        return tracker;
+    }
+
+    private void startTracking(WifiTracker tracker)  throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+        mScannerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                tracker.startTracking();
+                latch.countDown();
+            }
+        });
+        latch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
+    private void sendScanResultsAndProcess(WifiTracker tracker) throws InterruptedException {
+        mAccessPointsChangedLatch = new CountDownLatch(1);
+        Intent i = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+        tracker.mReceiver.onReceive(mContext, i);
+
+        mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
+    private void updateScores() {
+        Bundle attr1 = new Bundle();
+        attr1.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve1);
+        ScoredNetwork sc1 =
+                new ScoredNetwork(
+                        NETWORK_KEY_1,
+                        mockCurve1,
+                        false /* meteredHint */,
+                        attr1);
+
+        Bundle attr2 = new Bundle();
+        attr2.putParcelable(ScoredNetwork.ATTRIBUTES_KEY_BADGING_CURVE, mockBadgeCurve2);
+        ScoredNetwork sc2 =
+                new ScoredNetwork(
+                        NETWORK_KEY_2,
+                        mockCurve2,
+                        false /* meteredHint */,
+                        attr2);
+
+        WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
+        scoreCache.updateScores(Arrays.asList(sc1, sc2));
+    }
+
     @Test
     public void testAccessPointListenerSetWhenLookingUpUsingScanResults() {
         ScanResult scanResult = new ScanResult();
@@ -47,7 +296,7 @@
         scanResult.capabilities = "";
 
         WifiTracker tracker = new WifiTracker(
-                InstrumentationRegistry.getTargetContext(), null, true, true);
+                InstrumentationRegistry.getTargetContext(), null, mLooper, true, true);
 
         AccessPoint result = tracker.getCachedOrCreate(scanResult, new ArrayList<AccessPoint>());
         assertTrue(result.mAccessPointListener != null);
@@ -63,9 +312,125 @@
         configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
 
         WifiTracker tracker = new WifiTracker(
-                InstrumentationRegistry.getTargetContext(), null, true, true);
+                InstrumentationRegistry.getTargetContext(), null, mLooper, true, true);
 
         AccessPoint result = tracker.getCachedOrCreate(configuration, new ArrayList<AccessPoint>());
         assertTrue(result.mAccessPointListener != null);
     }
+
+    @Test
+    public void startAndStopTrackingShouldRegisterAndUnregisterScoreCache()
+            throws InterruptedException {
+        WifiTracker tracker = createMockedWifiTracker();
+
+        // Test register
+        startTracking(tracker);
+        verify(mockNetworkScoreManager)
+                .registerNetworkScoreCache(
+                          Matchers.anyInt(),
+                          mScoreCacheCaptor.capture(),
+                          Matchers.anyInt());
+
+        WifiNetworkScoreCache scoreCache = mScoreCacheCaptor.getValue();
+
+        // Test unregister
+        tracker.stopTracking();
+
+        verify(mockNetworkScoreManager)
+                .unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, scoreCache);
+    }
+
+    @Test
+    public void startTrackingShouldRequestScoresForCurrentAccessPoints() throws InterruptedException {
+        // Start the tracker and inject the initial scan results and then stop tracking
+        WifiTracker tracker =  createTrackerAndInjectInitialScanResults();
+
+        tracker.stopTracking();
+        mRequestedKeys.clear();
+
+        mRequestScoresLatch = new CountDownLatch(2);
+        startTracking(tracker);
+        mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+
+        assertTrue(mRequestedKeys.contains(NETWORK_KEY_1));
+        assertTrue(mRequestedKeys.contains(NETWORK_KEY_2));
+    }
+
+    @Test
+    public void scoreCacheUpdateScoresShouldTriggerOnAccessPointsChanged() throws InterruptedException {
+        WifiTracker tracker = createMockedWifiTracker();
+        startTracking(tracker);
+        sendScanResultsAndProcess(tracker);
+
+        updateScoresAndWaitForAccessPointsChangedCallback();
+    }
+
+    private void updateScoresAndWaitForAccessPointsChangedCallback() throws InterruptedException {
+        mAccessPointsChangedLatch = new CountDownLatch(2);
+        updateScores();
+        mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void scoreCacheUpdateScoresShouldChangeSortOrder() throws InterruptedException {
+        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        List<AccessPoint> aps = tracker.getAccessPoints();
+        assertTrue(aps.size() == 2);
+        assertEquals(aps.get(0).getSsidStr(), SSID_1);
+        assertEquals(aps.get(1).getSsidStr(), SSID_2);
+
+        updateScoresAndWaitForAccessPointsChangedCallback();
+
+        aps = tracker.getAccessPoints();
+        assertTrue(aps.size() == 2);
+        assertEquals(aps.get(0).getSsidStr(), SSID_2);
+        assertEquals(aps.get(1).getSsidStr(), SSID_1);
+
+    }
+
+    @Test
+    public void scoreCacheUpdateScoresShouldInsertBadgeIntoAccessPoint() throws InterruptedException {
+        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        updateScoresAndWaitForAccessPointsChangedCallback();
+
+        List<AccessPoint> aps = tracker.getAccessPoints();
+
+        for (AccessPoint ap : aps) {
+            if (ap.getSsidStr().equals(SSID_1)) {
+                assertEquals(BADGE_1, ap.getBadge());
+            } else if (ap.getSsidStr().equals(SSID_2)) {
+                assertEquals(BADGE_2, ap.getBadge());
+            }
+        }
+    }
+
+    @Test
+    public void scoresShouldBeRequestedForNewScanResultOnly()  throws InterruptedException {
+        mRequestScoresLatch = new CountDownLatch(2);
+        WifiTracker tracker = createTrackerAndInjectInitialScanResults();
+        mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+        mRequestedKeys.clear();
+
+        String ssid = "ssid3";
+        String bssid = "00:00:00:00:00:00";
+        ScanResult newResult = new ScanResult(
+                WifiSsid.createFromAsciiEncoded(ssid),
+                bssid,
+                0, // hessid
+                0, //anqpDomainId
+                null, // osuProviders
+                "", // capabilities
+                RSSI_1,
+                0, // frequency
+                SystemClock.elapsedRealtime() * 1000);
+        when(mockWifiManager.getScanResults())
+                .thenReturn(Arrays.asList(buildScanResult1(), buildScanResult2(), newResult));
+
+        mRequestScoresLatch = new CountDownLatch(1);
+        sendScanResultsAndProcess(tracker);
+        mRequestScoresLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS);
+
+        assertEquals(1, mRequestedKeys.size());
+        assertTrue(mRequestedKeys.contains(new NetworkKey(new WifiKey('"' + ssid + '"', bssid))));
+    }
 }
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 d8082c4..c95cac5 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
@@ -255,6 +255,7 @@
 
         Bundle bundle = new Bundle();
         bundle.putInt("com.android.settings.icon", 161803);
+        bundle.putString("com.android.settings.icon_package", "abc");
         bundle.putString("com.android.settings.summary", "dynamic-summary");
         when(mIContentProvider.call(anyString(),
                 eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_ICON))), eq(URI_GET_ICON), any()))
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 710214c..069e83a 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -7,6 +7,7 @@
     src/com/android/providers/settings/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := telephony-common ims-common
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_PACKAGE_NAME := SettingsProvider
 LOCAL_CERTIFICATE := platform
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
new file mode 100644
index 0000000..19ce3d0
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -0,0 +1,1655 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.annotation.NonNull;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.providers.settings.GlobalSettingsProto;
+import android.providers.settings.SecureSettingsProto;
+import android.providers.settings.SettingProto;
+import android.providers.settings.SettingsServiceDumpProto;
+import android.providers.settings.SystemSettingsProto;
+import android.providers.settings.UserSettingsProto;
+import android.util.SparseBooleanArray;
+import android.util.proto.ProtoOutputStream;
+
+/** @hide */
+class SettingsProtoDumpUtil {
+    private SettingsProtoDumpUtil() {}
+
+    static void dumpProtoLocked(SettingsProvider.SettingsRegistry settingsRegistry,
+            ProtoOutputStream proto) {
+        // Global settings
+        SettingsState globalSettings = settingsRegistry.getSettingsLocked(
+                SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
+        long globalSettingsToken = proto.start(SettingsServiceDumpProto.GLOBAL_SETTINGS);
+        dumpProtoGlobalSettingsLocked(globalSettings, proto);
+        proto.end(globalSettingsToken);
+
+        // Per-user settings
+        SparseBooleanArray users = settingsRegistry.getKnownUsersLocked();
+        final int userCount = users.size();
+        for (int i = 0; i < userCount; i++) {
+            long userSettingsToken = proto.start(SettingsServiceDumpProto.USER_SETTINGS);
+            dumpProtoUserSettingsLocked(
+                    settingsRegistry, UserHandle.of(users.keyAt(i)), proto);
+            proto.end(userSettingsToken);
+        }
+    }
+
+    /**
+     * Dump all settings of a user as a proto buf.
+     *
+     * @param settingsRegistry
+     * @param user The user the settings should be dumped for
+     * @param proto The proto buf stream to dump to
+     */
+    private static void dumpProtoUserSettingsLocked(
+            SettingsProvider.SettingsRegistry settingsRegistry,
+            @NonNull UserHandle user,
+            @NonNull ProtoOutputStream proto) {
+        proto.write(UserSettingsProto.USER_ID, user.getIdentifier());
+
+        SettingsState secureSettings = settingsRegistry.getSettingsLocked(
+                SettingsProvider.SETTINGS_TYPE_SECURE, user.getIdentifier());
+        long secureSettingsToken = proto.start(UserSettingsProto.SECURE_SETTINGS);
+        dumpProtoSecureSettingsLocked(secureSettings, proto);
+        proto.end(secureSettingsToken);
+
+        SettingsState systemSettings = settingsRegistry.getSettingsLocked(
+                SettingsProvider.SETTINGS_TYPE_SYSTEM, user.getIdentifier());
+        long systemSettingsToken = proto.start(UserSettingsProto.SYSTEM_SETTINGS);
+        dumpProtoSystemSettingsLocked(systemSettings, proto);
+        proto.end(systemSettingsToken);
+    }
+
+    private static void dumpProtoGlobalSettingsLocked(
+            @NonNull SettingsState s, @NonNull ProtoOutputStream p) {
+        dumpSetting(s, p,
+                Settings.Global.ADD_USERS_WHEN_LOCKED,
+                GlobalSettingsProto.ADD_USERS_WHEN_LOCKED);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
+                GlobalSettingsProto.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.AIRPLANE_MODE_ON,
+                GlobalSettingsProto.AIRPLANE_MODE_ON);
+        dumpSetting(s, p,
+                Settings.Global.THEATER_MODE_ON,
+                GlobalSettingsProto.THEATER_MODE_ON);
+        dumpSetting(s, p,
+                Settings.Global.RADIO_BLUETOOTH,
+                GlobalSettingsProto.RADIO_BLUETOOTH);
+        dumpSetting(s, p,
+                Settings.Global.RADIO_WIFI,
+                GlobalSettingsProto.RADIO_WIFI);
+        dumpSetting(s, p,
+                Settings.Global.RADIO_WIMAX,
+                GlobalSettingsProto.RADIO_WIMAX);
+        dumpSetting(s, p,
+                Settings.Global.RADIO_CELL,
+                GlobalSettingsProto.RADIO_CELL);
+        dumpSetting(s, p,
+                Settings.Global.RADIO_NFC,
+                GlobalSettingsProto.RADIO_NFC);
+        dumpSetting(s, p,
+                Settings.Global.AIRPLANE_MODE_RADIOS,
+                GlobalSettingsProto.AIRPLANE_MODE_RADIOS);
+        dumpSetting(s, p,
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+                GlobalSettingsProto.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_DISABLED_PROFILES,
+                GlobalSettingsProto.BLUETOOTH_DISABLED_PROFILES);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_INTEROPERABILITY_LIST,
+                GlobalSettingsProto.BLUETOOTH_INTEROPERABILITY_LIST);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_SLEEP_POLICY,
+                GlobalSettingsProto.WIFI_SLEEP_POLICY);
+        dumpSetting(s, p,
+                Settings.Global.AUTO_TIME,
+                GlobalSettingsProto.AUTO_TIME);
+        dumpSetting(s, p,
+                Settings.Global.AUTO_TIME_ZONE,
+                GlobalSettingsProto.AUTO_TIME_ZONE);
+        dumpSetting(s, p,
+                Settings.Global.CAR_DOCK_SOUND,
+                GlobalSettingsProto.CAR_DOCK_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.CAR_UNDOCK_SOUND,
+                GlobalSettingsProto.CAR_UNDOCK_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.DESK_DOCK_SOUND,
+                GlobalSettingsProto.DESK_DOCK_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.DESK_UNDOCK_SOUND,
+                GlobalSettingsProto.DESK_UNDOCK_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.DOCK_SOUNDS_ENABLED,
+                GlobalSettingsProto.DOCK_SOUNDS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
+                GlobalSettingsProto.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY);
+        dumpSetting(s, p,
+                Settings.Global.LOCK_SOUND,
+                GlobalSettingsProto.LOCK_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.UNLOCK_SOUND,
+                GlobalSettingsProto.UNLOCK_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.TRUSTED_SOUND,
+                GlobalSettingsProto.TRUSTED_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.LOW_BATTERY_SOUND,
+                GlobalSettingsProto.LOW_BATTERY_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.POWER_SOUNDS_ENABLED,
+                GlobalSettingsProto.POWER_SOUNDS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WIRELESS_CHARGING_STARTED_SOUND,
+                GlobalSettingsProto.WIRELESS_CHARGING_STARTED_SOUND);
+        dumpSetting(s, p,
+                Settings.Global.CHARGING_SOUNDS_ENABLED,
+                GlobalSettingsProto.CHARGING_SOUNDS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+                GlobalSettingsProto.STAY_ON_WHILE_PLUGGED_IN);
+        dumpSetting(s, p,
+                Settings.Global.BUGREPORT_IN_POWER_MENU,
+                GlobalSettingsProto.BUGREPORT_IN_POWER_MENU);
+        dumpSetting(s, p,
+                Settings.Global.ADB_ENABLED,
+                GlobalSettingsProto.ADB_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DEBUG_VIEW_ATTRIBUTES,
+                GlobalSettingsProto.DEBUG_VIEW_ATTRIBUTES);
+        dumpSetting(s, p,
+                Settings.Global.ASSISTED_GPS_ENABLED,
+                GlobalSettingsProto.ASSISTED_GPS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_ON,
+                GlobalSettingsProto.BLUETOOTH_ON);
+        dumpSetting(s, p,
+                Settings.Global.CDMA_CELL_BROADCAST_SMS,
+                GlobalSettingsProto.CDMA_CELL_BROADCAST_SMS);
+        dumpSetting(s, p,
+                Settings.Global.CDMA_ROAMING_MODE,
+                GlobalSettingsProto.CDMA_ROAMING_MODE);
+        dumpSetting(s, p,
+                Settings.Global.CDMA_SUBSCRIPTION_MODE,
+                GlobalSettingsProto.CDMA_SUBSCRIPTION_MODE);
+        dumpSetting(s, p,
+                Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
+                GlobalSettingsProto.DATA_ACTIVITY_TIMEOUT_MOBILE);
+        dumpSetting(s, p,
+                Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
+                GlobalSettingsProto.DATA_ACTIVITY_TIMEOUT_WIFI);
+        dumpSetting(s, p,
+                Settings.Global.DATA_ROAMING,
+                GlobalSettingsProto.DATA_ROAMING);
+        dumpSetting(s, p,
+                Settings.Global.MDC_INITIAL_MAX_RETRY,
+                GlobalSettingsProto.MDC_INITIAL_MAX_RETRY);
+        dumpSetting(s, p,
+                Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
+                GlobalSettingsProto.FORCE_ALLOW_ON_EXTERNAL);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
+                GlobalSettingsProto.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
+                GlobalSettingsProto.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
+                GlobalSettingsProto.DEVELOPMENT_SETTINGS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_PROVISIONED,
+                GlobalSettingsProto.DEVICE_PROVISIONED);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
+                GlobalSettingsProto.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DISPLAY_SIZE_FORCED,
+                GlobalSettingsProto.DISPLAY_SIZE_FORCED);
+        dumpSetting(s, p,
+                Settings.Global.DISPLAY_SCALING_FORCE,
+                GlobalSettingsProto.DISPLAY_SCALING_FORCE);
+        dumpSetting(s, p,
+                Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
+                GlobalSettingsProto.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
+        dumpSetting(s, p,
+                Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
+                GlobalSettingsProto.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+        dumpSetting(s, p,
+                Settings.Global.HDMI_CONTROL_ENABLED,
+                GlobalSettingsProto.HDMI_CONTROL_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.HDMI_SYSTEM_AUDIO_ENABLED,
+                GlobalSettingsProto.HDMI_SYSTEM_AUDIO_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
+                GlobalSettingsProto.HDMI_CONTROL_AUTO_WAKEUP_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
+                GlobalSettingsProto.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.MHL_INPUT_SWITCHING_ENABLED,
+                GlobalSettingsProto.MHL_INPUT_SWITCHING_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.MHL_POWER_CHARGE_ENABLED,
+                GlobalSettingsProto.MHL_POWER_CHARGE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.MOBILE_DATA,
+                GlobalSettingsProto.MOBILE_DATA);
+        dumpSetting(s, p,
+                Settings.Global.MOBILE_DATA_ALWAYS_ON,
+                GlobalSettingsProto.MOBILE_DATA_ALWAYS_ON);
+        dumpSetting(s, p,
+                Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
+                GlobalSettingsProto.CONNECTIVITY_METRICS_BUFFER_SIZE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_ENABLED,
+                GlobalSettingsProto.NETSTATS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_POLL_INTERVAL,
+                GlobalSettingsProto.NETSTATS_POLL_INTERVAL);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE,
+                GlobalSettingsProto.NETSTATS_TIME_CACHE_MAX_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES,
+                GlobalSettingsProto.NETSTATS_GLOBAL_ALERT_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_SAMPLE_ENABLED,
+                GlobalSettingsProto.NETSTATS_SAMPLE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_DEV_BUCKET_DURATION,
+                GlobalSettingsProto.NETSTATS_DEV_BUCKET_DURATION);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_DEV_PERSIST_BYTES,
+                GlobalSettingsProto.NETSTATS_DEV_PERSIST_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_DEV_ROTATE_AGE,
+                GlobalSettingsProto.NETSTATS_DEV_ROTATE_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_DEV_DELETE_AGE,
+                GlobalSettingsProto.NETSTATS_DEV_DELETE_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_BUCKET_DURATION,
+                GlobalSettingsProto.NETSTATS_UID_BUCKET_DURATION);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_PERSIST_BYTES,
+                GlobalSettingsProto.NETSTATS_UID_PERSIST_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_ROTATE_AGE,
+                GlobalSettingsProto.NETSTATS_UID_ROTATE_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_DELETE_AGE,
+                GlobalSettingsProto.NETSTATS_UID_DELETE_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION,
+                GlobalSettingsProto.NETSTATS_UID_TAG_BUCKET_DURATION);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES,
+                GlobalSettingsProto.NETSTATS_UID_TAG_PERSIST_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
+                GlobalSettingsProto.NETSTATS_UID_TAG_ROTATE_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETSTATS_UID_TAG_DELETE_AGE,
+                GlobalSettingsProto.NETSTATS_UID_TAG_DELETE_AGE);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_PREFERENCE,
+                GlobalSettingsProto.NETWORK_PREFERENCE);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SCORER_APP,
+                GlobalSettingsProto.NETWORK_SCORER_APP);
+        dumpSetting(s, p,
+                Settings.Global.NITZ_UPDATE_DIFF,
+                GlobalSettingsProto.NITZ_UPDATE_DIFF);
+        dumpSetting(s, p,
+                Settings.Global.NITZ_UPDATE_SPACING,
+                GlobalSettingsProto.NITZ_UPDATE_SPACING);
+        dumpSetting(s, p,
+                Settings.Global.NTP_SERVER,
+                GlobalSettingsProto.NTP_SERVER);
+        dumpSetting(s, p,
+                Settings.Global.NTP_TIMEOUT,
+                GlobalSettingsProto.NTP_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Global.STORAGE_BENCHMARK_INTERVAL,
+                GlobalSettingsProto.STORAGE_BENCHMARK_INTERVAL);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
+                GlobalSettingsProto.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
+                GlobalSettingsProto.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
+                GlobalSettingsProto.DNS_RESOLVER_MIN_SAMPLES);
+        dumpSetting(s, p,
+                Settings.Global.DNS_RESOLVER_MAX_SAMPLES,
+                GlobalSettingsProto.DNS_RESOLVER_MAX_SAMPLES);
+        dumpSetting(s, p,
+                Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE,
+                GlobalSettingsProto.OTA_DISABLE_AUTOMATIC_UPDATE);
+        dumpSetting(s, p,
+                Settings.Global.PACKAGE_VERIFIER_ENABLE,
+                GlobalSettingsProto.PACKAGE_VERIFIER_ENABLE);
+        dumpSetting(s, p,
+                Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
+                GlobalSettingsProto.PACKAGE_VERIFIER_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+                GlobalSettingsProto.PACKAGE_VERIFIER_DEFAULT_RESPONSE);
+        dumpSetting(s, p,
+                Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE,
+                GlobalSettingsProto.PACKAGE_VERIFIER_SETTING_VISIBLE);
+        dumpSetting(s, p,
+                Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB,
+                GlobalSettingsProto.PACKAGE_VERIFIER_INCLUDE_ADB);
+        dumpSetting(s, p,
+                Settings.Global.FSTRIM_MANDATORY_INTERVAL,
+                GlobalSettingsProto.FSTRIM_MANDATORY_INTERVAL);
+        dumpSetting(s, p,
+                Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS,
+                GlobalSettingsProto.PDP_WATCHDOG_POLL_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
+                GlobalSettingsProto.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
+                GlobalSettingsProto.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
+                GlobalSettingsProto.PDP_WATCHDOG_TRIGGER_PACKET_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT,
+                GlobalSettingsProto.PDP_WATCHDOG_ERROR_POLL_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
+                GlobalSettingsProto.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.SAMPLING_PROFILER_MS,
+                GlobalSettingsProto.SAMPLING_PROFILER_MS);
+        dumpSetting(s, p,
+                Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL,
+                GlobalSettingsProto.SETUP_PREPAID_DATA_SERVICE_URL);
+        dumpSetting(s, p,
+                Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
+                GlobalSettingsProto.SETUP_PREPAID_DETECTION_TARGET_URL);
+        dumpSetting(s, p,
+                Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
+                GlobalSettingsProto.SETUP_PREPAID_DETECTION_REDIR_HOST);
+        dumpSetting(s, p,
+                Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
+                GlobalSettingsProto.SMS_OUTGOING_CHECK_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
+                GlobalSettingsProto.SMS_OUTGOING_CHECK_MAX_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.SMS_SHORT_CODE_CONFIRMATION,
+                GlobalSettingsProto.SMS_SHORT_CODE_CONFIRMATION);
+        dumpSetting(s, p,
+                Settings.Global.SMS_SHORT_CODE_RULE,
+                GlobalSettingsProto.SMS_SHORT_CODE_RULE);
+        dumpSetting(s, p,
+                Settings.Global.TCP_DEFAULT_INIT_RWND,
+                GlobalSettingsProto.TCP_DEFAULT_INIT_RWND);
+        dumpSetting(s, p,
+                Settings.Global.TETHER_SUPPORTED,
+                GlobalSettingsProto.TETHER_SUPPORTED);
+        dumpSetting(s, p,
+                Settings.Global.TETHER_DUN_REQUIRED,
+                GlobalSettingsProto.TETHER_DUN_REQUIRED);
+        dumpSetting(s, p,
+                Settings.Global.TETHER_DUN_APN,
+                GlobalSettingsProto.TETHER_DUN_APN);
+        dumpSetting(s, p,
+                Settings.Global.CARRIER_APP_WHITELIST,
+                GlobalSettingsProto.CARRIER_APP_WHITELIST);
+        dumpSetting(s, p,
+                Settings.Global.USB_MASS_STORAGE_ENABLED,
+                GlobalSettingsProto.USB_MASS_STORAGE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.USE_GOOGLE_MAIL,
+                GlobalSettingsProto.USE_GOOGLE_MAIL);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
+                GlobalSettingsProto.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED,
+                GlobalSettingsProto.WEBVIEW_FALLBACK_LOGIC_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_PROVIDER,
+                GlobalSettingsProto.WEBVIEW_PROVIDER);
+        dumpSetting(s, p,
+                Settings.Global.WEBVIEW_MULTIPROCESS,
+                GlobalSettingsProto.WEBVIEW_MULTIPROCESS);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
+                GlobalSettingsProto.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
+                GlobalSettingsProto.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_AVOID_BAD_WIFI,
+                GlobalSettingsProto.NETWORK_AVOID_BAD_WIFI);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_DISPLAY_ON,
+                GlobalSettingsProto.WIFI_DISPLAY_ON);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_DISPLAY_CERTIFICATION_ON,
+                GlobalSettingsProto.WIFI_DISPLAY_CERTIFICATION_ON);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_DISPLAY_WPS_CONFIG,
+                GlobalSettingsProto.WIFI_DISPLAY_WPS_CONFIG);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                GlobalSettingsProto.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+        dumpSetting(s, p,
+                Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                GlobalSettingsProto.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
+                GlobalSettingsProto.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_COUNTRY_CODE,
+                GlobalSettingsProto.WIFI_COUNTRY_CODE);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
+                GlobalSettingsProto.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_IDLE_MS,
+                GlobalSettingsProto.WIFI_IDLE_MS);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT,
+                GlobalSettingsProto.WIFI_NUM_OPEN_NETWORKS_KEPT);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_ON,
+                GlobalSettingsProto.WIFI_ON);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
+                GlobalSettingsProto.WIFI_SCAN_ALWAYS_AVAILABLE);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_WAKEUP_ENABLED,
+                GlobalSettingsProto.WIFI_WAKEUP_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                GlobalSettingsProto.NETWORK_RECOMMENDATIONS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
+                GlobalSettingsProto.BLE_SCAN_ALWAYS_AVAILABLE);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_SAVED_STATE,
+                GlobalSettingsProto.WIFI_SAVED_STATE);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
+                GlobalSettingsProto.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_ENHANCED_AUTO_JOIN,
+                GlobalSettingsProto.WIFI_ENHANCED_AUTO_JOIN);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_NETWORK_SHOW_RSSI,
+                GlobalSettingsProto.WIFI_NETWORK_SHOW_RSSI);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
+                GlobalSettingsProto.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_WATCHDOG_ON,
+                GlobalSettingsProto.WIFI_WATCHDOG_ON);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
+                GlobalSettingsProto.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED,
+                GlobalSettingsProto.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
+                GlobalSettingsProto.WIFI_VERBOSE_LOGGING_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
+                GlobalSettingsProto.WIFI_MAX_DHCP_RETRY_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+                GlobalSettingsProto.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN,
+                GlobalSettingsProto.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_FREQUENCY_BAND,
+                GlobalSettingsProto.WIFI_FREQUENCY_BAND);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_P2P_DEVICE_NAME,
+                GlobalSettingsProto.WIFI_P2P_DEVICE_NAME);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_REENABLE_DELAY_MS,
+                GlobalSettingsProto.WIFI_REENABLE_DELAY_MS);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS,
+                GlobalSettingsProto.WIFI_EPHEMERAL_OUT_OF_RANGE_TIMEOUT_MS);
+        dumpSetting(s, p,
+                Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
+                GlobalSettingsProto.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS);
+        dumpSetting(s, p,
+                Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
+                GlobalSettingsProto.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS);
+        dumpSetting(s, p,
+                Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
+                GlobalSettingsProto.PROVISIONING_APN_ALARM_DELAY_IN_MS);
+        dumpSetting(s, p,
+                Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+                GlobalSettingsProto.GPRS_REGISTER_CHECK_PERIOD_MS);
+        dumpSetting(s, p,
+                Settings.Global.WTF_IS_FATAL,
+                GlobalSettingsProto.WTF_IS_FATAL);
+        dumpSetting(s, p,
+                Settings.Global.MODE_RINGER,
+                GlobalSettingsProto.MODE_RINGER);
+        dumpSetting(s, p,
+                Settings.Global.OVERLAY_DISPLAY_DEVICES,
+                GlobalSettingsProto.OVERLAY_DISPLAY_DEVICES);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
+                GlobalSettingsProto.BATTERY_DISCHARGE_DURATION_THRESHOLD);
+        dumpSetting(s, p,
+                Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
+                GlobalSettingsProto.BATTERY_DISCHARGE_THRESHOLD);
+        dumpSetting(s, p,
+                Settings.Global.SEND_ACTION_APP_ERROR,
+                GlobalSettingsProto.SEND_ACTION_APP_ERROR);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_AGE_SECONDS,
+                GlobalSettingsProto.DROPBOX_AGE_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_MAX_FILES,
+                GlobalSettingsProto.DROPBOX_MAX_FILES);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_QUOTA_KB,
+                GlobalSettingsProto.DROPBOX_QUOTA_KB);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_QUOTA_PERCENT,
+                GlobalSettingsProto.DROPBOX_QUOTA_PERCENT);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_RESERVE_PERCENT,
+                GlobalSettingsProto.DROPBOX_RESERVE_PERCENT);
+        dumpSetting(s, p,
+                Settings.Global.DROPBOX_TAG_PREFIX,
+                GlobalSettingsProto.DROPBOX_TAG_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.ERROR_LOGCAT_PREFIX,
+                GlobalSettingsProto.ERROR_LOGCAT_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL,
+                GlobalSettingsProto.SYS_FREE_STORAGE_LOG_INTERVAL);
+        dumpSetting(s, p,
+                Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
+                GlobalSettingsProto.DISK_FREE_CHANGE_REPORTING_THRESHOLD);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+                GlobalSettingsProto.SYS_STORAGE_THRESHOLD_PERCENTAGE);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
+                GlobalSettingsProto.SYS_STORAGE_THRESHOLD_MAX_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
+                GlobalSettingsProto.SYS_STORAGE_FULL_THRESHOLD_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
+                GlobalSettingsProto.SYNC_MAX_RETRY_DELAY_IN_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.CONNECTIVITY_CHANGE_DELAY,
+                GlobalSettingsProto.CONNECTIVITY_CHANGE_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
+                GlobalSettingsProto.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS);
+        dumpSetting(s, p,
+                Settings.Global.PAC_CHANGE_DELAY,
+                GlobalSettingsProto.PAC_CHANGE_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_MODE,
+                GlobalSettingsProto.CAPTIVE_PORTAL_MODE);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_SERVER,
+                GlobalSettingsProto.CAPTIVE_PORTAL_SERVER);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_HTTPS_URL,
+                GlobalSettingsProto.CAPTIVE_PORTAL_HTTPS_URL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+                GlobalSettingsProto.CAPTIVE_PORTAL_HTTP_URL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL,
+                GlobalSettingsProto.CAPTIVE_PORTAL_FALLBACK_URL);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
+                GlobalSettingsProto.CAPTIVE_PORTAL_USE_HTTPS);
+        dumpSetting(s, p,
+                Settings.Global.CAPTIVE_PORTAL_USER_AGENT,
+                GlobalSettingsProto.CAPTIVE_PORTAL_USER_AGENT);
+        dumpSetting(s, p,
+                Settings.Global.NSD_ON,
+                GlobalSettingsProto.NSD_ON);
+        dumpSetting(s, p,
+                Settings.Global.SET_INSTALL_LOCATION,
+                GlobalSettingsProto.SET_INSTALL_LOCATION);
+        dumpSetting(s, p,
+                Settings.Global.DEFAULT_INSTALL_LOCATION,
+                GlobalSettingsProto.DEFAULT_INSTALL_LOCATION);
+        dumpSetting(s, p,
+                Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY,
+                GlobalSettingsProto.INET_CONDITION_DEBOUNCE_UP_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY,
+                GlobalSettingsProto.INET_CONDITION_DEBOUNCE_DOWN_DELAY);
+        dumpSetting(s, p,
+                Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
+                GlobalSettingsProto.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT);
+        dumpSetting(s, p,
+                Settings.Global.HTTP_PROXY,
+                GlobalSettingsProto.HTTP_PROXY);
+        dumpSetting(s, p,
+                Settings.Global.GLOBAL_HTTP_PROXY_HOST,
+                GlobalSettingsProto.GLOBAL_HTTP_PROXY_HOST);
+        dumpSetting(s, p,
+                Settings.Global.GLOBAL_HTTP_PROXY_PORT,
+                GlobalSettingsProto.GLOBAL_HTTP_PROXY_PORT);
+        dumpSetting(s, p,
+                Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+                GlobalSettingsProto.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+        dumpSetting(s, p,
+                Settings.Global.GLOBAL_HTTP_PROXY_PAC,
+                GlobalSettingsProto.GLOBAL_HTTP_PROXY_PAC);
+        dumpSetting(s, p,
+                Settings.Global.SET_GLOBAL_HTTP_PROXY,
+                GlobalSettingsProto.SET_GLOBAL_HTTP_PROXY);
+        dumpSetting(s, p,
+                Settings.Global.DEFAULT_DNS_SERVER,
+                GlobalSettingsProto.DEFAULT_DNS_SERVER);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_HEADSET_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_MAP_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_MAP_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_SAP_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_SAP_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_PAN_PRIORITY_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_PAN_PRIORITY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_IDLE_CONSTANTS,
+                GlobalSettingsProto.DEVICE_IDLE_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH,
+                GlobalSettingsProto.DEVICE_IDLE_CONSTANTS_WATCH);
+        dumpSetting(s, p,
+                Settings.Global.APP_IDLE_CONSTANTS,
+                GlobalSettingsProto.APP_IDLE_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.ALARM_MANAGER_CONSTANTS,
+                GlobalSettingsProto.ALARM_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.JOB_SCHEDULER_CONSTANTS,
+                GlobalSettingsProto.JOB_SCHEDULER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+                GlobalSettingsProto.SHORTCUT_MANAGER_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.WINDOW_ANIMATION_SCALE,
+                GlobalSettingsProto.WINDOW_ANIMATION_SCALE);
+        dumpSetting(s, p,
+                Settings.Global.TRANSITION_ANIMATION_SCALE,
+                GlobalSettingsProto.TRANSITION_ANIMATION_SCALE);
+        dumpSetting(s, p,
+                Settings.Global.ANIMATOR_DURATION_SCALE,
+                GlobalSettingsProto.ANIMATOR_DURATION_SCALE);
+        dumpSetting(s, p,
+                Settings.Global.FANCY_IME_ANIMATIONS,
+                GlobalSettingsProto.FANCY_IME_ANIMATIONS);
+        dumpSetting(s, p,
+                Settings.Global.COMPATIBILITY_MODE,
+                GlobalSettingsProto.COMPATIBILITY_MODE);
+        dumpSetting(s, p,
+                Settings.Global.EMERGENCY_TONE,
+                GlobalSettingsProto.EMERGENCY_TONE);
+        dumpSetting(s, p,
+                Settings.Global.CALL_AUTO_RETRY,
+                GlobalSettingsProto.CALL_AUTO_RETRY);
+        dumpSetting(s, p,
+                Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
+                GlobalSettingsProto.EMERGENCY_AFFORDANCE_NEEDED);
+        dumpSetting(s, p,
+                Settings.Global.PREFERRED_NETWORK_MODE,
+                GlobalSettingsProto.PREFERRED_NETWORK_MODE);
+        dumpSetting(s, p,
+                Settings.Global.DEBUG_APP,
+                GlobalSettingsProto.DEBUG_APP);
+        dumpSetting(s, p,
+                Settings.Global.WAIT_FOR_DEBUGGER,
+                GlobalSettingsProto.WAIT_FOR_DEBUGGER);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE,
+                GlobalSettingsProto.LOW_POWER_MODE);
+        dumpSetting(s, p,
+                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
+                GlobalSettingsProto.LOW_POWER_MODE_TRIGGER_LEVEL);
+        dumpSetting(s, p,
+                Settings.Global.ALWAYS_FINISH_ACTIVITIES,
+                GlobalSettingsProto.ALWAYS_FINISH_ACTIVITIES);
+        dumpSetting(s, p,
+                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED,
+                GlobalSettingsProto.DOCK_AUDIO_MEDIA_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.ENCODED_SURROUND_OUTPUT,
+                GlobalSettingsProto.ENCODED_SURROUND_OUTPUT);
+        dumpSetting(s, p,
+                Settings.Global.AUDIO_SAFE_VOLUME_STATE,
+                GlobalSettingsProto.AUDIO_SAFE_VOLUME_STATE);
+        dumpSetting(s, p,
+                Settings.Global.TZINFO_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.TZINFO_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.TZINFO_UPDATE_METADATA_URL,
+                GlobalSettingsProto.TZINFO_UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.SELINUX_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.SELINUX_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.SELINUX_UPDATE_METADATA_URL,
+                GlobalSettingsProto.SELINUX_UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.SMS_SHORT_CODES_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL,
+                GlobalSettingsProto.SMS_SHORT_CODES_UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.APN_DB_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.APN_DB_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.APN_DB_UPDATE_METADATA_URL,
+                GlobalSettingsProto.APN_DB_UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.CERT_PIN_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.CERT_PIN_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.CERT_PIN_UPDATE_METADATA_URL,
+                GlobalSettingsProto.CERT_PIN_UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.INTENT_FIREWALL_UPDATE_CONTENT_URL,
+                GlobalSettingsProto.INTENT_FIREWALL_UPDATE_CONTENT_URL);
+        dumpSetting(s, p,
+                Settings.Global.INTENT_FIREWALL_UPDATE_METADATA_URL,
+                GlobalSettingsProto.INTENT_FIREWALL_UPDATE_METADATA_URL);
+        dumpSetting(s, p,
+                Settings.Global.SELINUX_STATUS,
+                GlobalSettingsProto.SELINUX_STATUS);
+        dumpSetting(s, p,
+                Settings.Global.DEVELOPMENT_FORCE_RTL,
+                GlobalSettingsProto.DEVELOPMENT_FORCE_RTL);
+        dumpSetting(s, p,
+                Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
+                GlobalSettingsProto.LOW_BATTERY_SOUND_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
+                GlobalSettingsProto.WIFI_BOUNCE_DELAY_OVERRIDE_MS);
+        dumpSetting(s, p,
+                Settings.Global.POLICY_CONTROL,
+                GlobalSettingsProto.POLICY_CONTROL);
+        dumpSetting(s, p,
+                Settings.Global.ZEN_MODE,
+                GlobalSettingsProto.ZEN_MODE);
+        dumpSetting(s, p,
+                Settings.Global.ZEN_MODE_RINGER_LEVEL,
+                GlobalSettingsProto.ZEN_MODE_RINGER_LEVEL);
+        dumpSetting(s, p,
+                Settings.Global.ZEN_MODE_CONFIG_ETAG,
+                GlobalSettingsProto.ZEN_MODE_CONFIG_ETAG);
+        dumpSetting(s, p,
+                Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+                GlobalSettingsProto.HEADS_UP_NOTIFICATIONS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_NAME,
+                GlobalSettingsProto.DEVICE_NAME);
+        dumpSetting(s, p,
+                Settings.Global.NETWORK_SCORING_PROVISIONED,
+                GlobalSettingsProto.NETWORK_SCORING_PROVISIONED);
+        dumpSetting(s, p,
+                Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
+                GlobalSettingsProto.REQUIRE_PASSWORD_TO_DECRYPT);
+        dumpSetting(s, p,
+                Settings.Global.ENHANCED_4G_MODE_ENABLED,
+                GlobalSettingsProto.ENHANCED_4G_MODE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.VT_IMS_ENABLED,
+                GlobalSettingsProto.VT_IMS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WFC_IMS_ENABLED,
+                GlobalSettingsProto.WFC_IMS_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.WFC_IMS_MODE,
+                GlobalSettingsProto.WFC_IMS_MODE);
+        dumpSetting(s, p,
+                Settings.Global.WFC_IMS_ROAMING_MODE,
+                GlobalSettingsProto.WFC_IMS_ROAMING_MODE);
+        dumpSetting(s, p,
+                Settings.Global.WFC_IMS_ROAMING_ENABLED,
+                GlobalSettingsProto.WFC_IMS_ROAMING_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.LTE_SERVICE_FORCED,
+                GlobalSettingsProto.LTE_SERVICE_FORCED);
+        dumpSetting(s, p,
+                Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
+                GlobalSettingsProto.EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_EPHEMERAL_FEATURE,
+                GlobalSettingsProto.ENABLE_EPHEMERAL_FEATURE);
+        dumpSetting(s, p,
+                Settings.Global.UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS,
+                GlobalSettingsProto.UNINSTALLED_EPHEMERAL_APP_CACHE_DURATION_MILLIS);
+        dumpSetting(s, p,
+                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
+                GlobalSettingsProto.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED);
+        dumpSetting(s, p,
+                Settings.Global.BOOT_COUNT,
+                GlobalSettingsProto.BOOT_COUNT);
+        dumpSetting(s, p,
+                Settings.Global.SAFE_BOOT_DISALLOWED,
+                GlobalSettingsProto.SAFE_BOOT_DISALLOWED);
+        dumpSetting(s, p,
+                Settings.Global.DEVICE_DEMO_MODE,
+                GlobalSettingsProto.DEVICE_DEMO_MODE);
+        dumpSetting(s, p,
+                Settings.Global.RETAIL_DEMO_MODE_CONSTANTS,
+                GlobalSettingsProto.RETAIL_DEMO_MODE_CONSTANTS);
+        dumpSetting(s, p,
+                Settings.Global.DATABASE_DOWNGRADE_REASON,
+                GlobalSettingsProto.DATABASE_DOWNGRADE_REASON);
+        dumpSetting(s, p,
+                Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
+                GlobalSettingsProto.CONTACTS_DATABASE_WAL_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
+                GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_VOICE_PROMPT,
+                GlobalSettingsProto.MULTI_SIM_VOICE_PROMPT);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION,
+                GlobalSettingsProto.MULTI_SIM_DATA_CALL_SUBSCRIPTION);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION,
+                GlobalSettingsProto.MULTI_SIM_SMS_SUBSCRIPTION);
+        dumpSetting(s, p,
+                Settings.Global.MULTI_SIM_SMS_PROMPT,
+                GlobalSettingsProto.MULTI_SIM_SMS_PROMPT);
+        dumpSetting(s, p,
+                Settings.Global.NEW_CONTACT_AGGREGATOR,
+                GlobalSettingsProto.NEW_CONTACT_AGGREGATOR);
+        dumpSetting(s, p,
+                Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
+                GlobalSettingsProto.CONTACT_METADATA_SYNC_ENABLED);
+        dumpSetting(s, p,
+                Settings.Global.ENABLE_CELLULAR_ON_BOOT,
+                GlobalSettingsProto.ENABLE_CELLULAR_ON_BOOT);
+        dumpSetting(s, p,
+                Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
+                GlobalSettingsProto.MAX_NOTIFICATION_ENQUEUE_RATE);
+        dumpSetting(s, p,
+                Settings.Global.CELL_ON,
+                GlobalSettingsProto.CELL_ON);
+    }
+
+    /** Dump a single {@link SettingsState.Setting} to a proto buf */
+    private static void dumpSetting(@NonNull SettingsState settings,
+            @NonNull ProtoOutputStream proto, String settingName, long fieldId) {
+        SettingsState.Setting setting = settings.getSettingLocked(settingName);
+        long settingsToken = proto.start(fieldId);
+        proto.write(SettingProto.ID, setting.getId());
+        proto.write(SettingProto.NAME, settingName);
+        if (setting.getPackageName() != null) {
+            proto.write(SettingProto.PKG, setting.getPackageName());
+        }
+        proto.write(SettingProto.VALUE, setting.getValue());
+        if (setting.getDefaultValue() != null) {
+            proto.write(SettingProto.DEFAULT_VALUE, setting.getDefaultValue());
+            proto.write(SettingProto.DEFAULT_FROM_SYSTEM, setting.isDefaultFromSystem());
+        }
+        proto.end(settingsToken);
+    }
+
+    static void dumpProtoSecureSettingsLocked(
+            @NonNull SettingsState s, @NonNull ProtoOutputStream p) {
+        dumpSetting(s, p,
+                Settings.Secure.ANDROID_ID,
+                SecureSettingsProto.ANDROID_ID);
+        dumpSetting(s, p,
+                Settings.Secure.DEFAULT_INPUT_METHOD,
+                SecureSettingsProto.DEFAULT_INPUT_METHOD);
+        dumpSetting(s, p,
+                Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
+                SecureSettingsProto.SELECTED_INPUT_METHOD_SUBTYPE);
+        dumpSetting(s, p,
+                Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY,
+                SecureSettingsProto.INPUT_METHODS_SUBTYPE_HISTORY);
+        dumpSetting(s, p,
+                Settings.Secure.INPUT_METHOD_SELECTOR_VISIBILITY,
+                SecureSettingsProto.INPUT_METHOD_SELECTOR_VISIBILITY);
+        dumpSetting(s, p,
+                Settings.Secure.VOICE_INTERACTION_SERVICE,
+                SecureSettingsProto.VOICE_INTERACTION_SERVICE);
+        dumpSetting(s, p,
+                Settings.Secure.AUTO_FILL_SERVICE,
+                SecureSettingsProto.AUTO_FILL_SERVICE);
+        dumpSetting(s, p,
+                Settings.Secure.BLUETOOTH_HCI_LOG,
+                SecureSettingsProto.BLUETOOTH_HCI_LOG);
+        dumpSetting(s, p,
+                Settings.Secure.USER_SETUP_COMPLETE,
+                SecureSettingsProto.USER_SETUP_COMPLETE);
+        dumpSetting(s, p,
+                Settings.Secure.COMPLETED_CATEGORY_PREFIX,
+                SecureSettingsProto.COMPLETED_CATEGORY_PREFIX);
+        dumpSetting(s, p,
+                Settings.Secure.ENABLED_INPUT_METHODS,
+                SecureSettingsProto.ENABLED_INPUT_METHODS);
+        dumpSetting(s, p,
+                Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
+                SecureSettingsProto.DISABLED_SYSTEM_INPUT_METHODS);
+        dumpSetting(s, p,
+                Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
+                SecureSettingsProto.SHOW_IME_WITH_HARD_KEYBOARD);
+        dumpSetting(s, p,
+                Settings.Secure.ALWAYS_ON_VPN_APP,
+                SecureSettingsProto.ALWAYS_ON_VPN_APP);
+        dumpSetting(s, p,
+                Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
+                SecureSettingsProto.ALWAYS_ON_VPN_LOCKDOWN);
+        dumpSetting(s, p,
+                Settings.Secure.INSTALL_NON_MARKET_APPS,
+                SecureSettingsProto.INSTALL_NON_MARKET_APPS);
+        dumpSetting(s, p,
+                Settings.Secure.LOCATION_MODE,
+                SecureSettingsProto.LOCATION_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.LOCATION_PREVIOUS_MODE,
+                SecureSettingsProto.LOCATION_PREVIOUS_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
+                SecureSettingsProto.LOCK_TO_APP_EXIT_LOCKED);
+        dumpSetting(s, p,
+                Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
+                SecureSettingsProto.LOCK_SCREEN_LOCK_AFTER_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT,
+                SecureSettingsProto.LOCK_SCREEN_ALLOW_REMOTE_INPUT);
+        dumpSetting(s, p,
+                Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING,
+                SecureSettingsProto.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING);
+        dumpSetting(s, p,
+                Settings.Secure.TRUST_AGENTS_INITIALIZED,
+                SecureSettingsProto.TRUST_AGENTS_INITIALIZED);
+        dumpSetting(s, p,
+                Settings.Secure.PARENTAL_CONTROL_ENABLED,
+                SecureSettingsProto.PARENTAL_CONTROL_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
+                SecureSettingsProto.PARENTAL_CONTROL_LAST_UPDATE);
+        dumpSetting(s, p,
+                Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL,
+                SecureSettingsProto.PARENTAL_CONTROL_REDIRECT_URL);
+        dumpSetting(s, p,
+                Settings.Secure.SETTINGS_CLASSNAME,
+                SecureSettingsProto.SETTINGS_CLASSNAME);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED,
+                SecureSettingsProto.TOUCH_EXPLORATION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+                SecureSettingsProto.ENABLED_ACCESSIBILITY_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+                SecureSettingsProto.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
+                SecureSettingsProto.ACCESSIBILITY_SPEAK_PASSWORD);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
+                SecureSettingsProto.ACCESSIBILITY_SCRIPT_INJECTION);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
+                SecureSettingsProto.ACCESSIBILITY_SCREEN_READER_URL);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
+                SecureSettingsProto.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+                SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+                SecureSettingsProto.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_LOCALE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_PRESET);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_TYPE,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_EDGE_TYPE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_EDGE_COLOR,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_EDGE_COLOR);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_TYPEFACE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
+                SecureSettingsProto.ACCESSIBILITY_CAPTIONING_FONT_SCALE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+                SecureSettingsProto.ACCESSIBILITY_DISPLAY_DALTONIZER);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED,
+                SecureSettingsProto.ACCESSIBILITY_AUTOCLICK_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
+                SecureSettingsProto.ACCESSIBILITY_AUTOCLICK_DELAY);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
+                SecureSettingsProto.ACCESSIBILITY_LARGE_POINTER_ICON);
+        dumpSetting(s, p,
+                Settings.Secure.LONG_PRESS_TIMEOUT,
+                SecureSettingsProto.LONG_PRESS_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Secure.MULTI_PRESS_TIMEOUT,
+                SecureSettingsProto.MULTI_PRESS_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Secure.ENABLED_PRINT_SERVICES,
+                SecureSettingsProto.ENABLED_PRINT_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.DISABLED_PRINT_SERVICES,
+                SecureSettingsProto.DISABLED_PRINT_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.DISPLAY_DENSITY_FORCED,
+                SecureSettingsProto.DISPLAY_DENSITY_FORCED);
+        dumpSetting(s, p,
+                Settings.Secure.TTS_DEFAULT_RATE,
+                SecureSettingsProto.TTS_DEFAULT_RATE);
+        dumpSetting(s, p,
+                Settings.Secure.TTS_DEFAULT_PITCH,
+                SecureSettingsProto.TTS_DEFAULT_PITCH);
+        dumpSetting(s, p,
+                Settings.Secure.TTS_DEFAULT_SYNTH,
+                SecureSettingsProto.TTS_DEFAULT_SYNTH);
+        dumpSetting(s, p,
+                Settings.Secure.TTS_DEFAULT_LOCALE,
+                SecureSettingsProto.TTS_DEFAULT_LOCALE);
+        dumpSetting(s, p,
+                Settings.Secure.TTS_ENABLED_PLUGINS,
+                SecureSettingsProto.TTS_ENABLED_PLUGINS);
+        dumpSetting(s, p,
+                Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
+                SecureSettingsProto.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS);
+        dumpSetting(s, p,
+                Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
+                SecureSettingsProto.ALLOWED_GEOLOCATION_ORIGINS);
+        dumpSetting(s, p,
+                Settings.Secure.PREFERRED_TTY_MODE,
+                SecureSettingsProto.PREFERRED_TTY_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED,
+                SecureSettingsProto.ENHANCED_VOICE_PRIVACY_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.TTY_MODE_ENABLED,
+                SecureSettingsProto.TTY_MODE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.BACKUP_ENABLED,
+                SecureSettingsProto.BACKUP_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.BACKUP_AUTO_RESTORE,
+                SecureSettingsProto.BACKUP_AUTO_RESTORE);
+        dumpSetting(s, p,
+                Settings.Secure.BACKUP_PROVISIONED,
+                SecureSettingsProto.BACKUP_PROVISIONED);
+        dumpSetting(s, p,
+                Settings.Secure.BACKUP_TRANSPORT,
+                SecureSettingsProto.BACKUP_TRANSPORT);
+        dumpSetting(s, p,
+                Settings.Secure.LAST_SETUP_SHOWN,
+                SecureSettingsProto.LAST_SETUP_SHOWN);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY,
+                SecureSettingsProto.SEARCH_GLOBAL_SEARCH_ACTIVITY);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_NUM_PROMOTED_SOURCES,
+                SecureSettingsProto.SEARCH_NUM_PROMOTED_SOURCES);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MAX_RESULTS_TO_DISPLAY,
+                SecureSettingsProto.SEARCH_MAX_RESULTS_TO_DISPLAY);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MAX_RESULTS_PER_SOURCE,
+                SecureSettingsProto.SEARCH_MAX_RESULTS_PER_SOURCE);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_WEB_RESULTS_OVERRIDE_LIMIT,
+                SecureSettingsProto.SEARCH_WEB_RESULTS_OVERRIDE_LIMIT);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_PROMOTED_SOURCE_DEADLINE_MILLIS,
+                SecureSettingsProto.SEARCH_PROMOTED_SOURCE_DEADLINE_MILLIS);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_SOURCE_TIMEOUT_MILLIS,
+                SecureSettingsProto.SEARCH_SOURCE_TIMEOUT_MILLIS);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_PREFILL_MILLIS,
+                SecureSettingsProto.SEARCH_PREFILL_MILLIS);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MAX_STAT_AGE_MILLIS,
+                SecureSettingsProto.SEARCH_MAX_STAT_AGE_MILLIS);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MAX_SOURCE_EVENT_AGE_MILLIS,
+                SecureSettingsProto.SEARCH_MAX_SOURCE_EVENT_AGE_MILLIS);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MIN_IMPRESSIONS_FOR_SOURCE_RANKING,
+                SecureSettingsProto.SEARCH_MIN_IMPRESSIONS_FOR_SOURCE_RANKING);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MIN_CLICKS_FOR_SOURCE_RANKING,
+                SecureSettingsProto.SEARCH_MIN_CLICKS_FOR_SOURCE_RANKING);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_MAX_SHORTCUTS_RETURNED,
+                SecureSettingsProto.SEARCH_MAX_SHORTCUTS_RETURNED);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_QUERY_THREAD_CORE_POOL_SIZE,
+                SecureSettingsProto.SEARCH_QUERY_THREAD_CORE_POOL_SIZE);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_QUERY_THREAD_MAX_POOL_SIZE,
+                SecureSettingsProto.SEARCH_QUERY_THREAD_MAX_POOL_SIZE);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_SHORTCUT_REFRESH_CORE_POOL_SIZE,
+                SecureSettingsProto.SEARCH_SHORTCUT_REFRESH_CORE_POOL_SIZE);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE,
+                SecureSettingsProto.SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_THREAD_KEEPALIVE_SECONDS,
+                SecureSettingsProto.SEARCH_THREAD_KEEPALIVE_SECONDS);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT,
+                SecureSettingsProto.SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT);
+        dumpSetting(s, p,
+                Settings.Secure.MOUNT_PLAY_NOTIFICATION_SND,
+                SecureSettingsProto.MOUNT_PLAY_NOTIFICATION_SND);
+        dumpSetting(s, p,
+                Settings.Secure.MOUNT_UMS_AUTOSTART,
+                SecureSettingsProto.MOUNT_UMS_AUTOSTART);
+        dumpSetting(s, p,
+                Settings.Secure.MOUNT_UMS_PROMPT,
+                SecureSettingsProto.MOUNT_UMS_PROMPT);
+        dumpSetting(s, p,
+                Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED,
+                SecureSettingsProto.MOUNT_UMS_NOTIFY_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ANR_SHOW_BACKGROUND,
+                SecureSettingsProto.ANR_SHOW_BACKGROUND);
+        dumpSetting(s, p,
+                Settings.Secure.VOICE_RECOGNITION_SERVICE,
+                SecureSettingsProto.VOICE_RECOGNITION_SERVICE);
+        dumpSetting(s, p,
+                Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
+                SecureSettingsProto.PACKAGE_VERIFIER_USER_CONSENT);
+        dumpSetting(s, p,
+                Settings.Secure.SELECTED_SPELL_CHECKER,
+                SecureSettingsProto.SELECTED_SPELL_CHECKER);
+        dumpSetting(s, p,
+                Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE,
+                SecureSettingsProto.SELECTED_SPELL_CHECKER_SUBTYPE);
+        dumpSetting(s, p,
+                Settings.Secure.SPELL_CHECKER_ENABLED,
+                SecureSettingsProto.SPELL_CHECKER_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
+                SecureSettingsProto.INCALL_POWER_BUTTON_BEHAVIOR);
+        dumpSetting(s, p,
+                Settings.Secure.INCALL_BACK_BUTTON_BEHAVIOR,
+                SecureSettingsProto.INCALL_BACK_BUTTON_BEHAVIOR);
+        dumpSetting(s, p,
+                Settings.Secure.WAKE_GESTURE_ENABLED,
+                SecureSettingsProto.WAKE_GESTURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.DOZE_ENABLED,
+                SecureSettingsProto.DOZE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.DOZE_ALWAYS_ON,
+                SecureSettingsProto.DOZE_ALWAYS_ON);
+        dumpSetting(s, p,
+                Settings.Secure.DOZE_PULSE_ON_PICK_UP,
+                SecureSettingsProto.DOZE_PULSE_ON_PICK_UP);
+        dumpSetting(s, p,
+                Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
+                SecureSettingsProto.DOZE_PULSE_ON_DOUBLE_TAP);
+        dumpSetting(s, p,
+                Settings.Secure.UI_NIGHT_MODE,
+                SecureSettingsProto.UI_NIGHT_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.SCREENSAVER_ENABLED,
+                SecureSettingsProto.SCREENSAVER_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.SCREENSAVER_COMPONENTS,
+                SecureSettingsProto.SCREENSAVER_COMPONENTS);
+        dumpSetting(s, p,
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+                SecureSettingsProto.SCREENSAVER_ACTIVATE_ON_DOCK);
+        dumpSetting(s, p,
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+                SecureSettingsProto.SCREENSAVER_ACTIVATE_ON_SLEEP);
+        dumpSetting(s, p,
+                Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+                SecureSettingsProto.SCREENSAVER_DEFAULT_COMPONENT);
+        dumpSetting(s, p,
+                Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
+                SecureSettingsProto.NFC_PAYMENT_DEFAULT_COMPONENT);
+        dumpSetting(s, p,
+                Settings.Secure.NFC_PAYMENT_FOREGROUND,
+                SecureSettingsProto.NFC_PAYMENT_FOREGROUND);
+        dumpSetting(s, p,
+                Settings.Secure.SMS_DEFAULT_APPLICATION,
+                SecureSettingsProto.SMS_DEFAULT_APPLICATION);
+        dumpSetting(s, p,
+                Settings.Secure.DIALER_DEFAULT_APPLICATION,
+                SecureSettingsProto.DIALER_DEFAULT_APPLICATION);
+        dumpSetting(s, p,
+                Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
+                SecureSettingsProto.EMERGENCY_ASSISTANCE_APPLICATION);
+        dumpSetting(s, p,
+                Settings.Secure.ASSIST_STRUCTURE_ENABLED,
+                SecureSettingsProto.ASSIST_STRUCTURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
+                SecureSettingsProto.ASSIST_SCREENSHOT_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
+                SecureSettingsProto.ASSIST_DISCLOSURE_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
+                SecureSettingsProto.ENABLED_NOTIFICATION_ASSISTANT);
+        dumpSetting(s, p,
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                SecureSettingsProto.ENABLED_NOTIFICATION_LISTENERS);
+        dumpSetting(s, p,
+                Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+                SecureSettingsProto.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+        dumpSetting(s, p,
+                Settings.Secure.SYNC_PARENT_SOUNDS,
+                SecureSettingsProto.SYNC_PARENT_SOUNDS);
+        dumpSetting(s, p,
+                Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
+                SecureSettingsProto.IMMERSIVE_MODE_CONFIRMATIONS);
+        dumpSetting(s, p,
+                Settings.Secure.PRINT_SERVICE_SEARCH_URI,
+                SecureSettingsProto.PRINT_SERVICE_SEARCH_URI);
+        dumpSetting(s, p,
+                Settings.Secure.PAYMENT_SERVICE_SEARCH_URI,
+                SecureSettingsProto.PAYMENT_SERVICE_SEARCH_URI);
+        dumpSetting(s, p,
+                Settings.Secure.SKIP_FIRST_USE_HINTS,
+                SecureSettingsProto.SKIP_FIRST_USE_HINTS);
+        dumpSetting(s, p,
+                Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS,
+                SecureSettingsProto.UNSAFE_VOLUME_MUSIC_ACTIVE_MS);
+        dumpSetting(s, p,
+                Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                SecureSettingsProto.LOCK_SCREEN_SHOW_NOTIFICATIONS);
+        dumpSetting(s, p,
+                Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
+                SecureSettingsProto.TV_INPUT_HIDDEN_INPUTS);
+        dumpSetting(s, p,
+                Settings.Secure.TV_INPUT_CUSTOM_LABELS,
+                SecureSettingsProto.TV_INPUT_CUSTOM_LABELS);
+        dumpSetting(s, p,
+                Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED,
+                SecureSettingsProto.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED);
+        dumpSetting(s, p,
+                Settings.Secure.SLEEP_TIMEOUT,
+                SecureSettingsProto.SLEEP_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.Secure.DOUBLE_TAP_TO_WAKE,
+                SecureSettingsProto.DOUBLE_TAP_TO_WAKE);
+        dumpSetting(s, p,
+                Settings.Secure.ASSISTANT,
+                SecureSettingsProto.ASSISTANT);
+        dumpSetting(s, p,
+                Settings.Secure.CAMERA_GESTURE_DISABLED,
+                SecureSettingsProto.CAMERA_GESTURE_DISABLED);
+        dumpSetting(s, p,
+                Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
+                SecureSettingsProto.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED);
+        dumpSetting(s, p,
+                Settings.Secure.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+                SecureSettingsProto.CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
+                SecureSettingsProto.NIGHT_DISPLAY_ACTIVATED);
+        dumpSetting(s, p,
+                Settings.Secure.NIGHT_DISPLAY_AUTO_MODE,
+                SecureSettingsProto.NIGHT_DISPLAY_AUTO_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
+                SecureSettingsProto.NIGHT_DISPLAY_CUSTOM_START_TIME);
+        dumpSetting(s, p,
+                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,
+                Settings.Secure.VR_DISPLAY_MODE,
+                SecureSettingsProto.VR_DISPLAY_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.CARRIER_APPS_HANDLED,
+                SecureSettingsProto.CARRIER_APPS_HANDLED);
+        dumpSetting(s, p,
+                Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH,
+                SecureSettingsProto.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH);
+        dumpSetting(s, p,
+                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
+                SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
+                SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN);
+        dumpSetting(s, p,
+                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED,
+                SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED);
+        dumpSetting(s, p,
+                Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
+                SecureSettingsProto.AUTOMATIC_STORAGE_MANAGER_LAST_RUN);
+        dumpSetting(s, p,
+                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,
+                Settings.Secure.DEMO_USER_SETUP_COMPLETE,
+                SecureSettingsProto.DEMO_USER_SETUP_COMPLETE);
+        dumpSetting(s, p,
+                Settings.Secure.WEB_ACTION_ENABLED,
+                SecureSettingsProto.WEB_ACTION_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.DEVICE_PAIRED,
+                SecureSettingsProto.DEVICE_PAIRED);
+    }
+
+    private static void dumpProtoSystemSettingsLocked(
+            @NonNull SettingsState s, @NonNull ProtoOutputStream p) {
+        dumpSetting(s, p,
+                Settings.System.END_BUTTON_BEHAVIOR,
+                SystemSettingsProto.END_BUTTON_BEHAVIOR);
+        dumpSetting(s, p,
+                Settings.System.ADVANCED_SETTINGS,
+                SystemSettingsProto.ADVANCED_SETTINGS);
+        dumpSetting(s, p,
+                Settings.System.BLUETOOTH_DISCOVERABILITY,
+                SystemSettingsProto.BLUETOOTH_DISCOVERABILITY);
+        dumpSetting(s, p,
+                Settings.System.BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+                SystemSettingsProto.BLUETOOTH_DISCOVERABILITY_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.System.FONT_SCALE,
+                SystemSettingsProto.FONT_SCALE);
+        dumpSetting(s, p,
+                Settings.System.SYSTEM_LOCALES,
+                SystemSettingsProto.SYSTEM_LOCALES);
+        dumpSetting(s, p,
+                Settings.System.SCREEN_OFF_TIMEOUT,
+                SystemSettingsProto.SCREEN_OFF_TIMEOUT);
+        dumpSetting(s, p,
+                Settings.System.SCREEN_BRIGHTNESS,
+                SystemSettingsProto.SCREEN_BRIGHTNESS);
+        dumpSetting(s, p,
+                Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
+                SystemSettingsProto.SCREEN_BRIGHTNESS_FOR_VR);
+        dumpSetting(s, p,
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                SystemSettingsProto.SCREEN_BRIGHTNESS_MODE);
+        dumpSetting(s, p,
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
+                SystemSettingsProto.SCREEN_AUTO_BRIGHTNESS_ADJ);
+        dumpSetting(s, p,
+                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
+                SystemSettingsProto.MODE_RINGER_STREAMS_AFFECTED);
+        dumpSetting(s, p,
+                Settings.System.MUTE_STREAMS_AFFECTED,
+                SystemSettingsProto.MUTE_STREAMS_AFFECTED);
+        dumpSetting(s, p,
+                Settings.System.VIBRATE_ON,
+                SystemSettingsProto.VIBRATE_ON);
+        dumpSetting(s, p,
+                Settings.System.VIBRATE_INPUT_DEVICES,
+                SystemSettingsProto.VIBRATE_INPUT_DEVICES);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_RING,
+                SystemSettingsProto.VOLUME_RING);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_SYSTEM,
+                SystemSettingsProto.VOLUME_SYSTEM);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_VOICE,
+                SystemSettingsProto.VOLUME_VOICE);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_MUSIC,
+                SystemSettingsProto.VOLUME_MUSIC);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_ALARM,
+                SystemSettingsProto.VOLUME_ALARM);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_NOTIFICATION,
+                SystemSettingsProto.VOLUME_NOTIFICATION);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_BLUETOOTH_SCO,
+                SystemSettingsProto.VOLUME_BLUETOOTH_SCO);
+        dumpSetting(s, p,
+                Settings.System.VOLUME_MASTER,
+                SystemSettingsProto.VOLUME_MASTER);
+        dumpSetting(s, p,
+                Settings.System.MASTER_MONO,
+                SystemSettingsProto.MASTER_MONO);
+        dumpSetting(s, p,
+                Settings.System.VIBRATE_IN_SILENT,
+                SystemSettingsProto.VIBRATE_IN_SILENT);
+        dumpSetting(s, p,
+                Settings.System.APPEND_FOR_LAST_AUDIBLE,
+                SystemSettingsProto.APPEND_FOR_LAST_AUDIBLE);
+        dumpSetting(s, p,
+                Settings.System.RINGTONE,
+                SystemSettingsProto.RINGTONE);
+        dumpSetting(s, p,
+                Settings.System.RINGTONE_CACHE,
+                SystemSettingsProto.RINGTONE_CACHE);
+        dumpSetting(s, p,
+                Settings.System.NOTIFICATION_SOUND,
+                SystemSettingsProto.NOTIFICATION_SOUND);
+        dumpSetting(s, p,
+                Settings.System.NOTIFICATION_SOUND_CACHE,
+                SystemSettingsProto.NOTIFICATION_SOUND_CACHE);
+        dumpSetting(s, p,
+                Settings.System.ALARM_ALERT,
+                SystemSettingsProto.ALARM_ALERT);
+        dumpSetting(s, p,
+                Settings.System.ALARM_ALERT_CACHE,
+                SystemSettingsProto.ALARM_ALERT_CACHE);
+        dumpSetting(s, p,
+                Settings.System.MEDIA_BUTTON_RECEIVER,
+                SystemSettingsProto.MEDIA_BUTTON_RECEIVER);
+        dumpSetting(s, p,
+                Settings.System.TEXT_AUTO_REPLACE,
+                SystemSettingsProto.TEXT_AUTO_REPLACE);
+        dumpSetting(s, p,
+                Settings.System.TEXT_AUTO_CAPS,
+                SystemSettingsProto.TEXT_AUTO_CAPS);
+        dumpSetting(s, p,
+                Settings.System.TEXT_AUTO_PUNCTUATE,
+                SystemSettingsProto.TEXT_AUTO_PUNCTUATE);
+        dumpSetting(s, p,
+                Settings.System.TEXT_SHOW_PASSWORD,
+                SystemSettingsProto.TEXT_SHOW_PASSWORD);
+        dumpSetting(s, p,
+                Settings.System.SHOW_GTALK_SERVICE_STATUS,
+                SystemSettingsProto.SHOW_GTALK_SERVICE_STATUS);
+        dumpSetting(s, p,
+                Settings.System.TIME_12_24,
+                SystemSettingsProto.TIME_12_24);
+        dumpSetting(s, p,
+                Settings.System.DATE_FORMAT,
+                SystemSettingsProto.DATE_FORMAT);
+        dumpSetting(s, p,
+                Settings.System.SETUP_WIZARD_HAS_RUN,
+                SystemSettingsProto.SETUP_WIZARD_HAS_RUN);
+        dumpSetting(s, p,
+                Settings.System.ACCELEROMETER_ROTATION,
+                SystemSettingsProto.ACCELEROMETER_ROTATION);
+        dumpSetting(s, p,
+                Settings.System.USER_ROTATION,
+                SystemSettingsProto.USER_ROTATION);
+        dumpSetting(s, p,
+                Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
+                SystemSettingsProto.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
+        dumpSetting(s, p,
+                Settings.System.VIBRATE_WHEN_RINGING,
+                SystemSettingsProto.VIBRATE_WHEN_RINGING);
+        dumpSetting(s, p,
+                Settings.System.DTMF_TONE_WHEN_DIALING,
+                SystemSettingsProto.DTMF_TONE_WHEN_DIALING);
+        dumpSetting(s, p,
+                Settings.System.DTMF_TONE_TYPE_WHEN_DIALING,
+                SystemSettingsProto.DTMF_TONE_TYPE_WHEN_DIALING);
+        dumpSetting(s, p,
+                Settings.System.HEARING_AID,
+                SystemSettingsProto.HEARING_AID);
+        dumpSetting(s, p,
+                Settings.System.TTY_MODE,
+                SystemSettingsProto.TTY_MODE);
+        dumpSetting(s, p,
+                Settings.System.SOUND_EFFECTS_ENABLED,
+                SystemSettingsProto.SOUND_EFFECTS_ENABLED);
+        dumpSetting(s, p,
+                Settings.System.HAPTIC_FEEDBACK_ENABLED,
+                SystemSettingsProto.HAPTIC_FEEDBACK_ENABLED);
+        dumpSetting(s, p,
+                Settings.System.NOTIFICATION_LIGHT_PULSE,
+                SystemSettingsProto.NOTIFICATION_LIGHT_PULSE);
+        dumpSetting(s, p,
+                Settings.System.POINTER_LOCATION,
+                SystemSettingsProto.POINTER_LOCATION);
+        dumpSetting(s, p,
+                Settings.System.SHOW_TOUCHES,
+                SystemSettingsProto.SHOW_TOUCHES);
+        dumpSetting(s, p,
+                Settings.System.WINDOW_ORIENTATION_LISTENER_LOG,
+                SystemSettingsProto.WINDOW_ORIENTATION_LISTENER_LOG);
+        dumpSetting(s, p,
+                Settings.System.LOCKSCREEN_SOUNDS_ENABLED,
+                SystemSettingsProto.LOCKSCREEN_SOUNDS_ENABLED);
+        dumpSetting(s, p,
+                Settings.System.LOCKSCREEN_DISABLED,
+                SystemSettingsProto.LOCKSCREEN_DISABLED);
+        dumpSetting(s, p,
+                Settings.System.SIP_RECEIVE_CALLS,
+                SystemSettingsProto.SIP_RECEIVE_CALLS);
+        dumpSetting(s, p,
+                Settings.System.SIP_CALL_OPTIONS,
+                SystemSettingsProto.SIP_CALL_OPTIONS);
+        dumpSetting(s, p,
+                Settings.System.SIP_ALWAYS,
+                SystemSettingsProto.SIP_ALWAYS);
+        dumpSetting(s, p,
+                Settings.System.SIP_ADDRESS_ONLY,
+                SystemSettingsProto.SIP_ADDRESS_ONLY);
+        dumpSetting(s, p,
+                Settings.System.POINTER_SPEED,
+                SystemSettingsProto.POINTER_SPEED);
+        dumpSetting(s, p,
+                Settings.System.LOCK_TO_APP_ENABLED,
+                SystemSettingsProto.LOCK_TO_APP_ENABLED);
+        dumpSetting(s, p,
+                Settings.System.EGG_MODE,
+                SystemSettingsProto.EGG_MODE);
+        dumpSetting(s, p,
+                Settings.System.WHEN_TO_MAKE_WIFI_CALLS,
+                SystemSettingsProto.WHEN_TO_MAKE_WIFI_CALLS);
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3e62158..6979995 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -17,6 +17,7 @@
 package com.android.providers.settings;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.backup.BackupManager;
@@ -61,9 +62,11 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.ByteStringUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
@@ -76,17 +79,22 @@
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 import static android.os.Process.ROOT_UID;
-import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.SHELL_UID;
+import static android.os.Process.SYSTEM_UID;
+
 
 /**
  * <p>
@@ -162,6 +170,7 @@
     public static final int SETTINGS_TYPE_GLOBAL = 0;
     public static final int SETTINGS_TYPE_SYSTEM = 1;
     public static final int SETTINGS_TYPE_SECURE = 2;
+    public static final int SETTINGS_TYPE_SSAID = 3;
 
     public static final int SETTINGS_TYPE_MASK = 0xF0000000;
     public static final int SETTINGS_TYPE_SHIFT = 28;
@@ -249,6 +258,9 @@
             case SETTINGS_TYPE_SYSTEM: {
                 return "SETTINGS_SYSTEM";
             }
+            case SETTINGS_TYPE_SSAID: {
+                return "SETTINGS_SSAID";
+            }
             default: {
                 return "UNKNOWN";
             }
@@ -262,6 +274,7 @@
 
     @Override
     public boolean onCreate() {
+        Settings.setInSystemServer();
         synchronized (mLock) {
             mUserManager = UserManager.get(getContext());
             mPackageManager = AppGlobals.getPackageManager();
@@ -591,6 +604,22 @@
         return cacheDir;
     }
 
+    /**
+     * Dump all settings as a proto buf.
+     *
+     * @param fd The file to dump to
+     */
+    void dumpProto(@NonNull FileDescriptor fd) {
+        ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        synchronized (mLock) {
+            SettingsProtoDumpUtil.dumpProtoLocked(mSettingsRegistry, proto);
+
+        }
+
+        proto.flush();
+    }
+
     public void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (mLock) {
             final long identity = Binder.clearCallingIdentity();
@@ -653,7 +682,7 @@
             pw.print(" value:"); pw.print(toDumpString(setting.getValue()));
             if (setting.getDefaultValue() != null) {
                 pw.print(" default:"); pw.print(setting.getDefaultValue());
-                pw.print(" defaultSystemSet:"); pw.print(setting.isDefaultSystemSet());
+                pw.print(" defaultSystemSet:"); pw.print(setting.isDefaultFromSystem());
             }
             if (setting.getTag() != null) {
                 pw.print(" tag:"); pw.print(setting.getTag());
@@ -704,6 +733,13 @@
                             UserHandle.getUserId(uid));
                 }
             }
+
+            @Override
+            public void onUidRemoved(int uid) {
+                synchronized (mLock) {
+                    mSettingsRegistry.onUidRemovedLocked(uid);
+                }
+            }
         };
 
         // package changes
@@ -813,7 +849,8 @@
             SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
                     SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
 
-            List<String> names = settingsState.getSettingNamesLocked();
+            List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_GLOBAL,
+                    UserHandle.USER_SYSTEM);
 
             final int nameCount = names.size();
 
@@ -836,6 +873,9 @@
             Slog.v(LOG_TAG, "getGlobalSetting(" + name + ")");
         }
 
+        // Ensure the caller can access the setting.
+        enforceSettingReadable(name, SETTINGS_TYPE_GLOBAL, UserHandle.getCallingUserId());
+
         // Get the value.
         synchronized (mLock) {
             return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_GLOBAL,
@@ -938,8 +978,7 @@
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
         synchronized (mLock) {
-            List<String> names = mSettingsRegistry.getSettingsNamesLocked(
-                    SETTINGS_TYPE_SECURE, callingUserId);
+            List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SECURE, callingUserId);
 
             final int nameCount = names.size();
 
@@ -957,8 +996,15 @@
                     continue;
                 }
 
-                Setting setting = mSettingsRegistry.getSettingLocked(
-                        SETTINGS_TYPE_SECURE, owningUserId, name);
+                // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+                // SETTINGS_FILE_SSAID, unless accessed by a system process.
+                final Setting setting;
+                if (isNewSsaidSetting(name)) {
+                    setting = getSsaidSettingLocked(owningUserId);
+                } else {
+                    setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE, owningUserId,
+                            name);
+                }
                 appendSettingToCursor(result, setting);
             }
 
@@ -974,6 +1020,9 @@
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
+        // Ensure the caller can access the setting.
+        enforceSettingReadable(name, SETTINGS_TYPE_SECURE, callingUserId);
+
         // Determine the owning user as some profile settings are cloned from the parent.
         final int owningUserId = resolveOwningUserIdForSecureSettingLocked(callingUserId, name);
 
@@ -986,11 +1035,43 @@
 
         // Get the value.
         synchronized (mLock) {
+            // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+            // SETTINGS_FILE_SSAID, unless accessed by a system process.
+            if (isNewSsaidSetting(name)) {
+                return getSsaidSettingLocked(owningUserId);
+            }
+
             return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE,
                     owningUserId, name);
         }
     }
 
+    private boolean isNewSsaidSetting(String name) {
+        return Settings.Secure.ANDROID_ID.equals(name)
+                && UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID;
+    }
+
+    private Setting getSsaidSettingLocked(int owningUserId) {
+        // Get uid of caller (key) used to store ssaid value
+        String name = Integer.toString(
+                UserHandle.getUid(owningUserId, UserHandle.getAppId(Binder.getCallingUid())));
+
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getSsaidSettingLocked(" + name + "," + owningUserId + ")");
+        }
+
+        // Retrieve the ssaid from the table if present.
+        final Setting ssaid = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId,
+                name);
+
+        // Lazy initialize ssaid if not yet present in ssaid table.
+        if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
+            return mSettingsRegistry.generateSsaidLocked(getCallingPackage(), owningUserId);
+        }
+
+        return ssaid;
+    }
+
     private boolean insertSecureSetting(String name, String value, String tag,
             boolean makeDefault, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
@@ -1104,8 +1185,7 @@
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
         synchronized (mLock) {
-            List<String> names = mSettingsRegistry.getSettingsNamesLocked(
-                    SETTINGS_TYPE_SYSTEM, callingUserId);
+            List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_SYSTEM, callingUserId);
 
             final int nameCount = names.size();
 
@@ -1136,6 +1216,9 @@
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
 
+        // Ensure the caller can access the setting.
+        enforceSettingReadable(name, SETTINGS_TYPE_SYSTEM, callingUserId);
+
         // Determine the owning user as some profile settings are cloned from the parent.
         final int owningUserId = resolveOwningUserIdForSystemSettingLocked(callingUserId, name);
 
@@ -1354,9 +1437,15 @@
                 && (parentId = getGroupParentLocked(userId)) != userId) {
             // The setting has a dependency and the profile has a parent
             String dependency = sSystemCloneFromParentOnDependency.get(setting);
-            Setting settingObj = getSecureSetting(dependency, userId);
-            if (settingObj != null && settingObj.getValue().equals("1")) {
-                return parentId;
+            // Lookup the dependency setting as ourselves, some callers may not have access to it.
+            final long token = Binder.clearCallingIdentity();
+            try {
+                Setting settingObj = getSecureSetting(dependency, userId);
+                if (settingObj != null && settingObj.getValue().equals("1")) {
+                    return parentId;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
         return resolveOwningUserIdLocked(userId, sSystemCloneToManagedSettings, setting);
@@ -1424,6 +1513,55 @@
         }
     }
 
+    private Set<String> getEphemeralAccessibleSettings(int settingsType) {
+        switch (settingsType) {
+            case SETTINGS_TYPE_GLOBAL:
+                return Settings.Global.EPHEMERAL_SETTINGS;
+            case SETTINGS_TYPE_SECURE:
+                return Settings.Secure.EPHEMERAL_SETTINGS;
+            case SETTINGS_TYPE_SYSTEM:
+                return Settings.System.EPHEMERAL_SETTINGS;
+            default:
+                throw new IllegalArgumentException("Invalid settings type: " + settingsType);
+        }
+    }
+
+    private List<String> getSettingsNamesLocked(int settingsType, int userId) {
+        ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
+        if (ai.isEphemeralApp()) {
+            return new ArrayList<String>(getEphemeralAccessibleSettings(settingsType));
+        } else {
+            return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
+        }
+    }
+
+    private void enforceSettingReadable(String settingName, int settingsType, int userId) {
+        if (UserHandle.getAppId(Binder.getCallingUid()) < Process.FIRST_APPLICATION_UID) {
+            return;
+        }
+        ApplicationInfo ai = getCallingApplicationInfoOrThrow(userId);
+        if (!ai.isEphemeralApp()) {
+            return;
+        }
+        if (!getEphemeralAccessibleSettings(settingsType).contains(settingName)) {
+            throw new SecurityException("Setting " + settingName + " is not accessible from"
+                    + " ephemeral package " + getCallingPackage());
+        }
+    }
+
+    private ApplicationInfo getCallingApplicationInfoOrThrow(int userId) {
+        ApplicationInfo ai = null;
+        try {
+            ai = mPackageManager.getApplicationInfo(getCallingPackage(), 0 , userId);
+        } catch (RemoteException ignored) {
+        }
+        if (ai == null) {
+            throw new IllegalStateException("Failed to lookup info for package "
+                    + getCallingPackage());
+        }
+        return ai;
+    }
+
     private PackageInfo getCallingPackageInfoOrThrow(int userId) {
         try {
             PackageInfo packageInfo = mPackageManager.getPackageInfo(
@@ -1493,7 +1631,7 @@
         value = value.substring(1);
 
         Setting settingValue = getSecureSetting(
-                Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
+                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED, owningUserId);
         if (settingValue == null) {
             return false;
         }
@@ -1818,6 +1956,9 @@
         private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
         private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
         private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
+        private static final String SETTINGS_FILE_SSAID = "settings_ssaid.xml";
+
+        private static final String SSAID_USER_KEY = "userkey";
 
         private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
 
@@ -1832,6 +1973,117 @@
             mGenerationRegistry = new GenerationRegistry(mLock);
             mBackupManager = new BackupManager(getContext());
             migrateAllLegacySettingsIfNeeded();
+            syncSsaidTableOnStart();
+        }
+
+        private void generateUserKeyLocked(int userId) {
+            // Generate a random key for each user used for creating a new ssaid.
+            final byte[] keyBytes = new byte[16];
+            final SecureRandom rand = new SecureRandom();
+            rand.nextBytes(keyBytes);
+
+            // Convert to string for storage in settings table.
+            final String userKey = ByteStringUtils.toString(keyBytes);
+
+            // Store the key in the ssaid table.
+            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
+            final boolean success = ssaidSettings.insertSettingLocked(SSAID_USER_KEY, userKey, null,
+                    true, SettingsState.SYSTEM_PACKAGE_NAME);
+
+            if (!success) {
+                throw new IllegalStateException("Ssaid settings not accessible");
+            }
+        }
+
+        public Setting generateSsaidLocked(String packageName, int userId) {
+            final PackageInfo packageInfo;
+            try {
+                packageInfo = mPackageManager.getPackageInfo(packageName,
+                        PackageManager.GET_SIGNATURES, userId);
+            } catch (RemoteException e) {
+                throw new IllegalStateException("Package info doesn't exist");
+            }
+
+            // Read the user's key from the ssaid table.
+            Setting userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
+            if (userKeySetting == null || userKeySetting.isNull()
+                    || userKeySetting.getValue() == null) {
+                // Lazy initialize and store the user key.
+                generateUserKeyLocked(userId);
+                userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
+                if (userKeySetting == null || userKeySetting.isNull()
+                        || userKeySetting.getValue() == null) {
+                    throw new IllegalStateException("User key not accessible");
+                }
+            }
+            final String userKey = userKeySetting.getValue();
+
+            // Convert the user's key back to a byte array.
+            final byte[] keyBytes = ByteStringUtils.toByteArray(userKey);
+            if (keyBytes == null || keyBytes.length != 16) {
+                throw new IllegalStateException("User key invalid");
+            }
+
+            final MessageDigest md;
+            try {
+                // Hash package name and signature.
+                md = MessageDigest.getInstance("SHA-256");
+            } catch (NoSuchAlgorithmException e) {
+                throw new IllegalStateException("HmacSHA256 is not available");
+            }
+            md.update(keyBytes);
+            md.update(packageInfo.packageName.getBytes(StandardCharsets.UTF_8));
+            md.update(packageInfo.signatures[0].toByteArray());
+
+            // Convert result to a string for storage in settings table. Only want first 64 bits.
+            final String ssaid = ByteStringUtils.toString(md.digest()).substring(0, 16)
+                    .toLowerCase();
+
+            // Save the ssaid in the ssaid table.
+            final String uid = Integer.toString(packageInfo.applicationInfo.uid);
+            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
+            final boolean success = ssaidSettings.insertSettingLocked(uid, ssaid, null, true,
+                    packageName);
+
+            if (!success) {
+                throw new IllegalStateException("Ssaid settings not accessible");
+            }
+
+            return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid);
+        }
+
+        public void syncSsaidTableOnStart() {
+            synchronized (mLock) {
+                // Verify that each user's packages and ssaid's are in sync.
+                for (UserInfo user : mUserManager.getUsers(true)) {
+                    // Get all uids for the user's packages.
+                    final List<PackageInfo> packages;
+                    try {
+                        packages = mPackageManager.getInstalledPackages(0, user.id).getList();
+                    } catch (RemoteException e) {
+                        throw new IllegalStateException("Package manager not available");
+                    }
+                    final Set<String> appUids = new HashSet<>();
+                    for (PackageInfo info : packages) {
+                        appUids.add(Integer.toString(info.applicationInfo.uid));
+                    }
+
+                    // Get all uids currently stored in the user's ssaid table.
+                    final Set<String> ssaidUids = new HashSet<>(
+                            getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id));
+                    ssaidUids.remove(SSAID_USER_KEY);
+
+                    // Perform a set difference for the appUids and ssaidUids.
+                    ssaidUids.removeAll(appUids);
+
+                    // If there are ssaidUids left over they need to be removed from the table.
+                    final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
+                            user.id);
+                    for (String uid : ssaidUids) {
+                        ssaidSettings.deleteSettingLocked(uid);
+                    }
+                }
+            }
         }
 
         public List<String> getSettingsNamesLocked(int type, int userId) {
@@ -1884,6 +2136,10 @@
             final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
             ensureSettingsStateLocked(systemKey);
 
+            // Ensure secure settings loaded.
+            final int ssaidKey = makeKey(SETTINGS_TYPE_SSAID, userId);
+            ensureSettingsStateLocked(ssaidKey);
+
             // Upgrade the settings to the latest version.
             UpgradeController upgrader = new UpgradeController(userId);
             upgrader.upgradeIfNeededLocked();
@@ -1936,6 +2192,23 @@
                 }
             }
 
+            // Nuke ssaid settings.
+            final int ssaidKey = makeKey(SETTINGS_TYPE_SSAID, userId);
+            final SettingsState ssaidSettingsState = mSettingsStates.get(ssaidKey);
+            if (ssaidSettingsState != null) {
+                if (permanently) {
+                    mSettingsStates.remove(ssaidKey);
+                    ssaidSettingsState.destroyLocked(null);
+                } else {
+                    ssaidSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(ssaidKey);
+                        }
+                    });
+                }
+            }
+
             // Nuke generation tracking data
             mGenerationRegistry.onUserRemoved(userId);
         }
@@ -1979,6 +2252,8 @@
             if (settingsState == null) {
                 return null;
             }
+
+            // getSettingLocked will return non-null result
             return settingsState.getSettingLocked(name);
         }
 
@@ -2040,7 +2315,7 @@
                         Setting setting = settingsState.getSettingLocked(name);
                         if (!SettingsState.isSystemPackage(getContext(),
                                 setting.getPackageName())) {
-                            if (setting.isDefaultSystemSet()) {
+                            if (setting.isDefaultFromSystem()) {
                                 if (settingsState.resetSettingLocked(name, packageName)) {
                                     notifyForSettingsChange(key, name);
                                 }
@@ -2054,7 +2329,7 @@
                 case Settings.RESET_MODE_TRUSTED_DEFAULTS: {
                     for (String name : settingsState.getSettingNamesLocked()) {
                         Setting setting = settingsState.getSettingLocked(name);
-                        if (setting.isDefaultSystemSet()) {
+                        if (setting.isDefaultFromSystem()) {
                             if (settingsState.resetSettingLocked(name, packageName)) {
                                 notifyForSettingsChange(key, name);
                             }
@@ -2079,6 +2354,12 @@
             }
         }
 
+        public void onUidRemovedLocked(int uid) {
+            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
+                    UserHandle.getUserId(uid));
+            ssaidSettings.deleteSettingLocked(Integer.toString(uid));
+        }
+
         private SettingsState peekSettingsStateLocked(int key) {
             SettingsState settingsState = mSettingsStates.get(key);
             if (settingsState != null) {
@@ -2300,6 +2581,10 @@
             return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
         }
 
+        private boolean isSsaidSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_SSAID;
+        }
+
         private File getSettingsFile(int key) {
             if (isGlobalSettingsKey(key)) {
                 final int userId = getUserIdFromKey(key);
@@ -2313,6 +2598,10 @@
                 final int userId = getUserIdFromKey(key);
                 return new File(Environment.getUserSystemDirectory(userId),
                         SETTINGS_FILE_SECURE);
+            } else if (isSsaidSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SSAID);
             } else {
                 throw new IllegalArgumentException("Invalid settings key:" + key);
             }
@@ -2336,7 +2625,8 @@
         private int getMaxBytesPerPackageForType(int type) {
             switch (type) {
                 case SETTINGS_TYPE_GLOBAL:
-                case SETTINGS_TYPE_SECURE: {
+                case SETTINGS_TYPE_SECURE:
+                case SETTINGS_TYPE_SSAID: {
                     return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
                 }
 
@@ -2374,7 +2664,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 136;
+            private static final int SETTINGS_VERSION = 137;
 
             private final int mUserId;
 
@@ -2447,6 +2737,10 @@
                 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
             }
 
+            private SettingsState getSsaidSettingsLocked(int userId) {
+                return getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
+            }
+
             private SettingsState getSystemSettingsLocked(int userId) {
                 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
             }
@@ -2776,6 +3070,53 @@
                     currentVersion = 136;
                 }
 
+                if (currentVersion == 136) {
+                    // Version 136: Store legacy SSAID for all apps currently installed on the
+                    // device as first step in migrating SSAID to be unique per application.
+
+                    final boolean isUpgrade;
+                    try {
+                        isUpgrade = mPackageManager.isUpgrade();
+                    } catch (RemoteException e) {
+                        throw new IllegalStateException("Package manager not available");
+                    }
+                    // Only retain legacy ssaid if the device is performing an OTA. After wiping
+                    // user data or first boot on a new device should use new ssaid generation.
+                    if (isUpgrade) {
+                        // Retrieve the legacy ssaid from the secure settings table.
+                        final Setting legacySsaidSetting = getSettingLocked(SETTINGS_TYPE_SECURE,
+                                userId, Settings.Secure.ANDROID_ID);
+                        if (legacySsaidSetting == null || legacySsaidSetting.isNull()
+                                || legacySsaidSetting.getValue() == null) {
+                            throw new IllegalStateException("Legacy ssaid not accessible");
+                        }
+                        final String legacySsaid = legacySsaidSetting.getValue();
+
+                        // Fill each uid with the legacy ssaid to be backwards compatible.
+                        final List<PackageInfo> packages;
+                        try {
+                            packages = mPackageManager.getInstalledPackages(0, userId).getList();
+                        } catch (RemoteException e) {
+                            throw new IllegalStateException("Package manager not available");
+                        }
+
+                        final SettingsState ssaidSettings = getSsaidSettingsLocked(userId);
+                        for (PackageInfo info : packages) {
+                            // Check if the UID already has an entry in the table.
+                            final String uid = Integer.toString(info.applicationInfo.uid);
+                            final Setting ssaid = ssaidSettings.getSettingLocked(uid);
+
+                            if (ssaid.isNull() || ssaid.getValue() == null) {
+                                // Android Id doesn't exist for this package so create it.
+                                ssaidSettings.insertSettingLocked(uid, legacySsaid, null, true,
+                                        info.packageName);
+                            }
+                        }
+                    }
+
+                    currentVersion = 137;
+                }
+
                 if (currentVersion != newVersion) {
                     Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index fecc938..2d59324 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -65,6 +65,7 @@
         }
 
         int opti = 0;
+        boolean dumpAsProto = false;
         while (opti < args.length) {
             String opt = args[opti];
             if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
@@ -74,16 +75,22 @@
             if ("-h".equals(opt)) {
                 MyShellCommand.dumpHelp(pw, true);
                 return;
+            } else if ("--proto".equals(opt)) {
+                dumpAsProto = true;
             } else {
                 pw.println("Unknown argument: " + opt + "; use -h for help");
             }
         }
 
-        long caller = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            mProvider.dumpInternal(fd, pw, args);
+            if (dumpAsProto) {
+                mProvider.dumpProto(fd);
+            } else {
+                mProvider.dumpInternal(fd, pw, args);
+            }
         } finally {
-            Binder.restoreCallingIdentity(caller);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -449,8 +456,9 @@
         static void dumpHelp(PrintWriter pw, boolean dumping) {
             if (dumping) {
                 pw.println("Settings provider dump options:");
-                pw.println("  [-h]");
+                pw.println("  [-h] [--proto]");
                 pw.println("  -h: print this help.");
+                pw.println("  --proto: dump as protobuf.");
             } else {
                 pw.println("Settings provider (settings) commands:");
                 pw.println("  help");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 8f37b98..a74be35 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -16,6 +16,9 @@
 
 package com.android.providers.settings;
 
+import static android.os.Process.FIRST_APPLICATION_UID;
+
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -30,6 +33,8 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.providers.settings.GlobalSettingsProto;
+import android.providers.settings.SettingsOperationProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
@@ -38,10 +43,14 @@
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
+
 import libcore.io.IoUtils;
 import libcore.util.Objects;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -56,8 +65,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.os.Process.FIRST_APPLICATION_UID;
-
 /**
  * This class contains the state for one type of settings. It is responsible
  * for saving the state asynchronously to an XML file after a mutation and
@@ -404,6 +411,38 @@
         }
     }
 
+    /**
+     * Dump historical operations as a proto buf.
+     *
+     * @param proto The proto buf stream to dump to
+     */
+    void dumpProtoHistoricalOperations(@NonNull ProtoOutputStream proto) {
+        synchronized (mLock) {
+            if (mHistoricalOperations == null) {
+                return;
+            }
+
+            final int operationCount = mHistoricalOperations.size();
+            for (int i = 0; i < operationCount; i++) {
+                int index = mNextHistoricalOpIdx - 1 - i;
+                if (index < 0) {
+                    index = operationCount + index;
+                }
+                HistoricalOperation operation = mHistoricalOperations.get(index);
+                long settingsOperationToken = proto.start(GlobalSettingsProto.HISTORICAL_OP);
+                proto.write(SettingsOperationProto.TIMESTAMP, operation.mTimestamp);
+                proto.write(SettingsOperationProto.OPERATION, operation.mOperation);
+                if (operation.mSetting != null) {
+                    // Only add the name of the setting, since we don't know the historical package
+                    // and values for it so they would be misleading to add here (all we could
+                    // add is what the current data is).
+                    proto.write(SettingsOperationProto.SETTING, operation.mSetting.getName());
+                }
+                proto.end(settingsOperationToken);
+            }
+        }
+    }
+
     public void dumpHistoricalOperations(PrintWriter pw) {
         synchronized (mLock) {
             if (mHistoricalOperations == null) {
@@ -544,7 +583,7 @@
 
                 writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),
                         setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),
-                        setting.getTag(), setting.isDefaultSystemSet());
+                        setting.getTag(), setting.isDefaultFromSystem());
 
                 if (DEBUG_PERSISTENCE) {
                     Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue());
@@ -763,7 +802,7 @@
         private String id;
         private String tag;
         // Whether the default is set by the system
-        private boolean defaultSystemSet;
+        private boolean defaultFromSystem;
 
         public Setting(Setting other) {
             name = other.name;
@@ -771,7 +810,7 @@
             defaultValue = other.defaultValue;
             packageName = other.packageName;
             id = other.id;
-            defaultSystemSet = other.defaultSystemSet;
+            defaultFromSystem = other.defaultFromSystem;
             tag = other.tag;
         }
 
@@ -798,7 +837,7 @@
             this.defaultValue = defaultValue;
             this.packageName = packageName;
             this.id = id;
-            this.defaultSystemSet = fromSystem;
+            this.defaultFromSystem = fromSystem;
         }
 
         public String getName() {
@@ -825,8 +864,8 @@
             return packageName;
         }
 
-        public boolean isDefaultSystemSet() {
-            return defaultSystemSet;
+        public boolean isDefaultFromSystem() {
+            return defaultFromSystem;
         }
 
         public String getId() {
@@ -854,22 +893,22 @@
             }
 
             String defaultValue = this.defaultValue;
-            boolean defaultSystemSet = this.defaultSystemSet;
+            boolean defaultFromSystem = this.defaultFromSystem;
             if (setDefault) {
                 if (!Objects.equal(value, this.defaultValue)
-                        && (!defaultSystemSet || callerSystem)) {
+                        && (!defaultFromSystem || callerSystem)) {
                     defaultValue = value;
                     // Default null means no default, so the tag is irrelevant
                     // since it is used to reset a settings subset their defaults.
                     // Also it is irrelevant if the system set the canonical default.
                     if (defaultValue == null) {
                         tag = null;
-                        defaultSystemSet = false;
+                        defaultFromSystem = false;
                     }
                 }
-                if (!defaultSystemSet && value != null) {
+                if (!defaultFromSystem && value != null) {
                     if (callerSystem) {
-                        defaultSystemSet = true;
+                        defaultFromSystem = true;
                     }
                 }
             }
@@ -879,11 +918,11 @@
                     && Objects.equal(defaultValue, this.defaultValue)
                     && Objects.equal(packageName, this.packageName)
                     && Objects.equal(tag, this.tag)
-                    && defaultSystemSet == this.defaultSystemSet) {
+                    && defaultFromSystem == this.defaultFromSystem) {
                 return false;
             }
 
-            init(name, value, tag, defaultValue, packageName, defaultSystemSet,
+            init(name, value, tag, defaultValue, packageName, defaultFromSystem,
                     String.valueOf(mNextId++));
             return true;
         }
@@ -892,7 +931,7 @@
             return "Setting{name=" + name + " value=" + value
                     + (defaultValue != null ? " default=" + defaultValue : "")
                     + " packageName=" + packageName + " tag=" + tag
-                    + " defaultSystemSet=" + defaultSystemSet + "}";
+                    + " defaultFromSystem=" + defaultFromSystem + "}";
         }
     }
 
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index 918410e..d039f03 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -9,7 +9,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files) \
     ../src/com/android/providers/settings/SettingsState.java
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test legacy-android-test
 
 LOCAL_PACKAGE_NAME := SettingsProviderTest
 
@@ -17,4 +17,4 @@
 
 LOCAL_CERTIFICATE := platform
 
-include $(BUILD_PACKAGE)
\ No newline at end of file
+include $(BUILD_PACKAGE)
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index 0424eb0..acd552d 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -12,6 +12,8 @@
     android-support-test \
     mockito-target-minus-junit4 \
     ub-uiautomator \
+    junit \
+    legacy-android-test \
 
 LOCAL_PACKAGE_NAME := ShellTests
 LOCAL_INSTRUMENTATION_FOR := Shell
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index ff76c56..f72d091 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -60,6 +60,7 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
     <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
     <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
     <!-- Physical hardware -->
@@ -130,6 +131,9 @@
     <!-- Assist -->
     <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
 
+    <!-- Doze mode temp whitelisting for notification dispatching. -->
+    <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
+
     <!-- Listen for keyboard attachment / detachment -->
     <uses-permission android:name="android.permission.TABLET_MODE" />
 
@@ -289,7 +293,7 @@
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
                   android:resizeableActivity="true"
-                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
                   android:theme="@style/RecentsTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
index a9d1fa9..152dbc5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
@@ -14,17 +14,13 @@
 
 package com.android.systemui.plugins;
 
-import android.annotation.Nullable;
 import android.app.Fragment;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 
 public abstract class PluginFragment extends Fragment implements Plugin {
 
-    private static final String KEY_PLUGIN_PACKAGE = "plugin_package_name";
     private Context mPluginContext;
 
     @Override
@@ -33,45 +29,17 @@
     }
 
     @Override
-    public void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (savedInstanceState != null) {
-            Context sysuiContext = getContext();
-            Context pluginContext = recreatePluginContext(sysuiContext, savedInstanceState);
-            onCreate(sysuiContext, pluginContext);
-        }
-        if (mPluginContext == null) {
-            throw new RuntimeException("PluginFragments must call super.onCreate("
-                    + "Context sysuiContext, Context pluginContext)");
-        }
+    public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
+        return super.getLayoutInflater(savedInstanceState).cloneInContext(getContext());
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putString(KEY_PLUGIN_PACKAGE, getContext().getPackageName());
     }
 
-    private Context recreatePluginContext(Context sysuiContext, Bundle savedInstanceState) {
-        final String pkg = savedInstanceState.getString(KEY_PLUGIN_PACKAGE);
-        try {
-            ApplicationInfo appInfo = sysuiContext.getPackageManager().getApplicationInfo(pkg, 0);
-            return PluginManager.getInstance(sysuiContext).getContext(appInfo, pkg);
-        } catch (NameNotFoundException e) {
-            throw new RuntimeException("Plugin with invalid package? " + pkg, e);
-        }
-    }
-
-    @Override
-    public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
-        return super.getLayoutInflater(savedInstanceState).cloneInContext(mPluginContext);
-    }
-
-    /**
-     * Should only be called after {@link Plugin#onCreate(Context, Context)}.
-     */
     @Override
     public Context getContext() {
-        return mPluginContext != null ? mPluginContext : super.getContext();
+        return mPluginContext;
     }
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index 47b97bd..9f44bd4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -177,8 +177,12 @@
                     if (DEBUG) Log.d(TAG, "onPluginConnected");
                     PluginPrefs.setHasPlugins(mContext);
                     PluginInfo<T> info = (PluginInfo<T>) msg.obj;
-                    info.mPlugin.onCreate(mContext, info.mPluginContext);
-                    mListener.onPluginConnected(info.mPlugin);
+                    if (!(msg.obj instanceof PluginFragment)) {
+                        // Only call onDestroy for plugins that aren't fragments, as fragments
+                        // will get the onCreate as part of the fragment lifecycle.
+                        info.mPlugin.onCreate(mContext, info.mPluginContext);
+                    }
+                    mListener.onPluginConnected(info.mPlugin, info.mPluginContext);
                     break;
                 case PLUGIN_DISCONNECTED:
                     if (DEBUG) Log.d(TAG, "onPluginDisconnected");
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
index b2f92d6..b488d2a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.plugins;
 
+import android.content.Context;
+
 /**
  * Interface for listening to plugins being connected.
  */
@@ -24,7 +26,7 @@
      * It may also be called in the future if the plugin package changes
      * and needs to be reloaded.
      */
-    void onPluginConnected(T plugin);
+    void onPluginConnected(T plugin, Context pluginContext);
 
     /**
      * Called when a plugin has been uninstalled/updated and should be removed
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index a9874fc..e21a282 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -37,7 +37,7 @@
 
     // This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
     // change in incompatible ways.
-    public static final int VERSION = 4;
+    public static final int VERSION = 5;
 
     String TAG = "QS";
 
@@ -105,24 +105,8 @@
         public abstract void setExpansion(float headerExpansionFraction);
         public abstract void setListening(boolean listening);
         public abstract void updateEverything();
-        public abstract void setActivityStarter(ActivityStarter activityStarter);
         public abstract void setCallback(Callback qsPanelCallback);
         public abstract View getExpandView();
     }
 
-    /**
-     * An interface to start activities. This is used to as a callback from the views to
-     * {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
-     * Keyguard.
-     */
-    public static interface ActivityStarter {
-
-        void startPendingIntentDismissingKeyguard(PendingIntent intent);
-        void startActivity(Intent intent, boolean dismissShade);
-        void startActivity(Intent intent, boolean dismissShade, Callback callback);
-
-        interface Callback {
-            void onActivityStarted(int resultCode);
-        }
-    }
 }
diff --git a/packages/SystemUI/res/anim/ic_dnd_disable_alpha_animation.xml b/packages/SystemUI/res/anim/ic_dnd_disable_alpha_animation.xml
deleted file mode 100644
index 21caab4..0000000
--- a/packages/SystemUI/res/anim/ic_dnd_disable_alpha_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:valueType="floatType"
-        android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_alpha_animation.xml b/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_alpha_animation.xml
deleted file mode 100644
index 21caab4..0000000
--- a/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_alpha_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:valueType="floatType"
-        android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_hotspot_disable_animation_root.xml b/packages/SystemUI/res/anim/ic_hotspot_disable_animation_root.xml
deleted file mode 100644
index 770c401..0000000
--- a/packages/SystemUI/res/anim/ic_hotspot_disable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_root.xml b/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_root.xml
deleted file mode 100644
index 770c401..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_root.xml b/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_root.xml
deleted file mode 100644
index 387ca29..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_root.xml
deleted file mode 100644
index 770c401..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_root.xml
deleted file mode 100644
index 387ca29..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_root.xml
deleted file mode 100644
index 770c401..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_root.xml
deleted file mode 100644
index 387ca29..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_location_disable_animation_root.xml
deleted file mode 100644
index 770c401..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_location_enable_animation_root.xml
deleted file mode 100644
index 387ca29..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_root.xml
deleted file mode 100644
index 72834c9..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.3"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_root.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_root.xml
deleted file mode 100644
index 85573e0..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_root.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/drawable/ic_access_alarms_small.xml b/packages/SystemUI/res/drawable/ic_access_alarms_small.xml
index 994274a..b94cc8e 100644
--- a/packages/SystemUI/res/drawable/ic_access_alarms_small.xml
+++ b/packages/SystemUI/res/drawable/ic_access_alarms_small.xml
@@ -18,9 +18,9 @@
     android:height="16dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0"
-    android:tint="?android:attr/colorControlNormal">
+    android:tint="?android:attr/textColorTertiary">
 
     <path
-        android:fillColor="#64ffffff"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml b/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml
index 13ed767..d755481 100644
--- a/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml
@@ -23,7 +23,4 @@
     <target
         android:name="bar01_0"
         android:animation="@anim/ic_dnd_disable_bar01_0_animation" />
-    <target
-        android:name="ic_dnd_disable"
-        android:animation="@anim/ic_dnd_disable_alpha_animation" />
 </animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml b/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml
index c0b2d69..f796d62 100644
--- a/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml
@@ -23,7 +23,4 @@
     <target
         android:name="outer_ring_merged"
         android:animation="@anim/ic_dnd_total_silence_disable_outer_ring_merged_animation" />
-    <target
-        android:name="ic_dnd_total_silence_disable"
-        android:animation="@anim/ic_dnd_total_silence_disable_alpha_animation" />
 </animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml b/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml
index 694c23f..e446a32 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_hotspot_disable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_hotspot_disable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_hotspot_disable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_enable.xml b/packages/SystemUI/res/drawable/ic_hotspot_enable.xml
index 31e7fe1..7a99630 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot_enable.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot_enable.xml
@@ -16,12 +16,10 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="root"
-    android:alpha="0.3"
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_hotspot"
         android:translateX="23.97354"
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml b/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml
index c5187dd..945e42f 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_hotspot_enable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_hotspot_enable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_hotspot_enable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml b/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
index 83f46e5..7641998 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
@@ -19,9 +19,7 @@
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:alpha="0.25"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_hotspot"
         android:translateX="23.97354"
diff --git a/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml b/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml
index 476c00d..aeda0a5 100644
--- a/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_invert_colors_disable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_invert_colors_disable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_invert_colors_disable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml b/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml
index 879066c..85928ac 100644
--- a/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_invert_colors_enable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_invert_colors_enable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_invert_colors_enable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml b/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml
new file mode 100644
index 0000000..7b29740
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_battery_saver.xml
@@ -0,0 +1,28 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:pathData="M5,3
+        l3.5,0 l0,-1.5 l7,0 l0,1.5 l3.5,0 l0,19.5 l-14,0z
+        M10.5,8.5 l0,3 l-3,0 l0,3 l3,0 l0,3 l3,0 l0,-3 l3,0 l0,-3 l-3,0 l0,-3 z"
+        android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
index 36eb418..3148a2c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
@@ -21,6 +21,6 @@
         android:tint="?android:attr/colorControlNormal">
 
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M26.0,11.8l3.8,3.8l-3.2,3.2l2.8,2.8l6.0,-6.0L24.0,4.2l-2.0,0.0l0.0,10.1l4.0,4.0L26.0,11.8zM10.8,8.2L8.0,11.0l13.2,13.2L10.0,35.3l2.8,2.8L22.0,29.0l0.0,15.2l2.0,0.0l8.6,-8.6l4.6,4.6l2.8,-2.8L10.8,8.2zM26.0,36.5L26.0,29.0l3.8,3.8L26.0,36.5z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
index 0fdbe1f..06a0886 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
@@ -17,10 +17,9 @@
         android:width="64dp"
         android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="48.0">
 
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
index d2e9eb2..794eb9e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
@@ -17,8 +17,7 @@
         android:width="64dp"
         android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="48.0">
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_circle.xml b/packages/SystemUI/res/drawable/ic_qs_circle.xml
index 57223cf..990cec6 100644
--- a/packages/SystemUI/res/drawable/ic_qs_circle.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_circle.xml
@@ -14,14 +14,13 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
+        android:width="40dp"
+        android:height="40dp"
         android:viewportWidth="2.2"
         android:viewportHeight="2.2">
 
     <path
-        android:strokeColor="#4DFFFFFF"
-        android:strokeWidth=".05"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M.1,1.1
         c0,.55  .45,1   1,1
         c.55,0  1,-.45  1,-1
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
index d11b6f4..439ee3b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_data_disabled.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:autoMirrored="true"
-        android:width="32.0dp"
-        android:height="32.0dp"
-        android:viewportWidth="40.0"
-        android:viewportHeight="40.0">
+        android:width="17dp"
+        android:height="17.0dp"
+        android:viewportWidth="20.0"
+        android:viewportHeight="20.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M19.0,6.41L17.59,5.0 12.0,10.59 6.41,5.0 5.0,6.41 10.59,12.0 5.0,17.59 6.41,19.0 12.0,13.41 17.59,19.0 19.0,17.59 13.41,12.0z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
index 164a557..9168dbc 100644
--- a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
@@ -17,9 +17,7 @@
     android:height="64dp"
     android:viewportHeight="24.0"
     android:viewportWidth="24.0"
-    android:alpha=".3"
-    android:width="64dp"
-    android:tint="?android:attr/colorControlNormal" >
+    android:width="64dp" >
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
index 7e2eca8..f4c20a9 100644
--- a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
@@ -17,8 +17,7 @@
         android:width="64dp"
         android:height="64dp"
         android:viewportWidth="48.0"
-        android:viewportHeight="48.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="48.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on_total_silence.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on_total_silence.xml
index 5f4fa11..fb26c09 100644
--- a/packages/SystemUI/res/drawable/ic_qs_dnd_on_total_silence.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on_total_silence.xml
@@ -17,8 +17,7 @@
         android:width="64dp"
         android:height="64dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
index 147a94b..6a3410a 100644
--- a/packages/SystemUI/res/drawable/ic_qs_minus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -17,8 +17,7 @@
     android:height="24.0dp"
     android:viewportHeight="48.0"
     android:viewportWidth="48.0"
-    android:width="24.0dp"
-    android:tint="?android:attr/colorControlNormal" >
+    android:width="24.0dp" >
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml
new file mode 100644
index 0000000..558f3d0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml
@@ -0,0 +1,31 @@
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M4 20h16V4H4v16z" />
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1 .9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0
+18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6 .35 -1 .98-1 1.72 0 1.1 .9 2 2
+2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml b/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml
new file mode 100644
index 0000000..becb18a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml
@@ -0,0 +1,31 @@
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M4 20h16V4H4v16z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1 .9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0
+18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6 .35 -1 .98-1 1.72 0 1.1 .9 2 2
+2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml b/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml
index b99dc03..aaca663 100644
--- a/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_night_display_off.xml
@@ -17,12 +17,10 @@
     android:width="64dp"
     android:height="64dp"
     android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:alpha="0.3"
-    android:tint="?android:attr/colorControlNormal">
+    android:viewportHeight="24">
 
     <path
-        android:fillColor="#FFFFFF"
+        android:fillColor="#FFF"
         android:pathData="M6,12c0,5.5,4.5,10,10,10c1,0,2-0.2,3-0.5c-4.1-1.3-7-5.1-7-9.5s2.9-8.3,7-9.5C18.1,2.2,17.1,2,16,2C10.5,2,6,6.5,6,12z" />
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml b/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml
index d875592..aaca663 100644
--- a/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_night_display_on.xml
@@ -17,11 +17,10 @@
     android:width="64dp"
     android:height="64dp"
     android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?android:attr/colorControlNormal">
+    android:viewportHeight="24">
 
     <path
-        android:fillColor="#FFFFFF"
+        android:fillColor="#FFF"
         android:pathData="M6,12c0,5.5,4.5,10,10,10c1,0,2-0.2,3-0.5c-4.1-1.3-7-5.1-7-9.5s2.9-8.3,7-9.5C18.1,2.2,17.1,2,16,2C10.5,2,6,6.5,6,12z" />
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_no_sim.xml b/packages/SystemUI/res/drawable/ic_qs_no_sim.xml
index 2d831b2..69869fe 100644
--- a/packages/SystemUI/res/drawable/ic_qs_no_sim.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_no_sim.xml
@@ -17,10 +17,9 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
 
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
index 1f254d1..393f51c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -17,8 +17,7 @@
     android:height="24.0dp"
     android:viewportHeight="48.0"
     android:viewportWidth="48.0"
-    android:width="24.0dp"
-    android:tint="?android:attr/colorControlNormal" >
+    android:width="24.0dp" >
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
index 0673848..b78d3bf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
@@ -18,8 +18,7 @@
         android:width="32.0dp"
         android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
         android:fillAlpha="0.3"
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
index fbf9e71..e055de7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
@@ -18,8 +18,7 @@
         android:width="32.0dp"
         android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
index 3a55623..195849a 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_1x.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="16.0dp"
+        android:width="32.0dp"
         android:height="32dp"
         android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="12.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M3.500000,11.000000L1.800000,11.000000L1.800000,4.400000L0.200000,5.100000L0.200000,3.700000l3.100000,-1.300000l0.200000,0.000000L3.500000,11.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
index e9f5a0b..8a48817 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
@@ -18,8 +18,7 @@
         android:width="32.0dp"
         android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
index 769d648..39cc94c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
@@ -18,8 +18,7 @@
         android:width="32.0dp"
         android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
         android:fillAlpha="0.3"
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
index ddd8065..68c4307 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_3g.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="17.333334dp"
+        android:width="32dp"
         android:height="32dp"
         android:viewportWidth="13.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="13.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M2.000000,6.000000l0.800000,0.000000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000s0.200000,-0.500000 0.200000,-0.900000c0.000000,-0.300000 -0.100000,-0.600000 -0.200000,-0.800000S3.200000,3.700000 2.900000,3.700000C2.700000,3.700000 2.500000,3.800000 2.300000,4.000000S2.100000,4.400000 2.100000,4.700000L0.500000,4.700000C0.500000,4.000000 0.700000,3.400000 1.100000,3.000000s1.000000,-0.600000 1.700000,-0.600000c0.800000,0.000000 1.400000,0.200000 1.900000,0.600000s0.700000,1.000000 0.700000,1.800000c0.000000,0.400000 -0.100000,0.700000 -0.300000,1.100000S4.600000,6.500000 4.300000,6.600000C4.700000,6.800000 5.000000,7.100000 5.200000,7.400000s0.300000,0.700000 0.300000,1.200000c0.000000,0.800000 -0.200000,1.400000 -0.700000,1.800000s-1.100000,0.700000 -1.900000,0.700000c-0.700000,0.000000 -1.300000,-0.200000 -1.800000,-0.600000s-0.700000,-1.000000 -0.700000,-1.800000L2.000000,8.700000C2.000000,9.000000 2.100000,9.300000 2.300000,9.500000s0.400000,0.300000 0.600000,0.300000c0.300000,0.000000 0.500000,-0.100000 0.700000,-0.300000S3.900000,9.000000 3.900000,8.600000c0.000000,-0.500000 -0.100000,-0.800000 -0.300000,-1.000000S3.200000,7.300000 2.800000,7.300000L2.000000,7.300000L2.000000,6.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
index 1bec1b8..012e95e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
@@ -18,8 +18,7 @@
         android:width="32.0dp"
         android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
index 8e1f8eb..61ecc9c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="16.0dp"
+        android:width="32.0dp"
         android:height="32dp"
         android:viewportWidth="12.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="12.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M4.600000,7.800000l0.700000,0.000000l0.000000,1.300000L4.600000,9.100000L4.600000,11.000000L3.000000,11.000000L3.000000,9.200000L0.100000,9.200000L0.000000,8.100000L3.000000,2.500000l1.700000,0.000000L4.700000,7.800000zM1.600000,7.800000L3.000000,7.800000l0.000000,-3.000000L2.900000,5.000000L1.600000,7.800000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
index e0c6b68..54c52bf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4g_plus.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M4.6,7.8l0.7,0.0l0.0,1.3L4.6,9.1L4.6,11.0L3.0,11.0L3.0,9.2L0.1,9.2L0.0,8.2l3.0,-5.7l1.7,0.0L4.6,7.8L4.6,7.8zM1.7,7.8L3.0,7.8l0.0,-3.0L2.9,5.0L1.7,7.8z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml b/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml
index 1c068e5..96e2fd4 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_carrier_network_change.xml
@@ -17,8 +17,7 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:name="dot1"
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
index 0a85392..dd5843d 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_disabled.xml
@@ -18,12 +18,11 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M21.799999,22.299999l-1.199999,-1.299999 0.000000,0.000000 -9.600000,-10.000000 0.000000,0.000000 -6.400000,-6.700000 -1.300000,1.300000 6.400000,6.700000 -8.700000,8.700000 16.900000,0.000000 2.600000,2.700001z"/>
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M21.000000,1.000000l-8.600000,8.600000 8.600000,9.100000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
index 4c90421..dd0f271 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_e.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="6.6666665dp"
+        android:width="32dp"
         android:height="32dp"
         android:viewportWidth="5.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="5.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M4.400000,7.300000L1.700000,7.300000l0.000000,2.400000l3.300000,0.000000L5.000000,11.000000L0.000000,11.000000L0.000000,2.500000l4.900000,0.000000l0.000000,1.300000L1.700000,3.800000l0.000000,2.100000l2.800000,0.000000L4.500000,7.300000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml
index db4df76..326373d 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_full_0.xml
@@ -18,8 +18,7 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
index 6e5439d..8baa4eb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
@@ -18,8 +18,7 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml
index 194edc3..bf19a71 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_full_2.xml
@@ -18,8 +18,7 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml
index b57af5c..01839e85 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_full_3.xml
@@ -18,8 +18,7 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml
index 7d754a8..48151ad 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_full_4.xml
@@ -18,8 +18,7 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
index 64aadf9..3b47c0d 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_g.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="9.333333dp"
+        android:width="32dp"
         android:height="32dp"
         android:viewportWidth="7.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="7.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M6.500000,9.900000c-0.200000,0.400000 -0.600000,0.700000 -1.000000,0.900000s-1.000000,0.400000 -1.800000,0.400000c-0.900000,0.000000 -1.700000,-0.300000 -2.200000,-0.800000S0.700000,9.000000 0.700000,7.900000L0.700000,5.600000c0.000000,-1.100000 0.300000,-1.900000 0.800000,-2.400000s1.200000,-0.800000 2.100000,-0.800000c1.000000,0.000000 1.700000,0.200000 2.100000,0.700000s0.700000,1.200000 0.700000,2.100000L4.700000,5.200000c0.000000,-0.500000 -0.100000,-0.900000 -0.200000,-1.100000S4.000000,3.700000 3.600000,3.700000c-0.400000,0.000000 -0.700000,0.200000 -0.900000,0.500000S2.300000,5.000000 2.300000,5.600000l0.000000,2.300000c0.000000,0.700000 0.100000,1.100000 0.300000,1.400000s0.600000,0.500000 1.000000,0.500000c0.300000,0.000000 0.600000,0.000000 0.700000,-0.100000s0.300000,-0.200000 0.400000,-0.300000L4.700000,7.800000L3.500000,7.800000L3.500000,6.600000l2.900000,0.000000L6.400000,9.900000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
index 31918a9..d694e61 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_h.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8.0dp"
+        android:width="32.0dp"
         android:height="32dp"
         android:viewportWidth="6.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="6.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M6.000000,11.000000L4.400000,11.000000L4.400000,7.500000L1.700000,7.500000L1.700000,11.000000L0.000000,11.000000L0.000000,2.500000l1.700000,0.000000l0.000000,3.700000l2.700000,0.000000L4.400000,2.500000L6.000000,2.500000L6.000000,11.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
index 4122b76..236fdac 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_in.xml
@@ -17,8 +17,7 @@
         android:width="6.0dp"
         android:height="32dp"
         android:viewportWidth="6.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M6.000000,15.700000l-3.000000,5.599999 -3.000000,-5.599999z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
index 8766075..a381d03e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_lte.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="17.333334dp"
+        android:width="32dp"
         android:height="32dp"
         android:viewportWidth="13.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="13.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M2.000000,9.700000l2.000000,0.000000L4.000000,11.000000L0.300000,11.000000L0.300000,2.500000L2.000000,2.500000L2.000000,9.700000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml b/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
index 5ff7d85..3bed28a 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_lte_plus.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M2.0,9.7l2.0,0.0L4.0,11.0L0.4,11.0L0.4,2.5L2.0,2.5L2.0,9.7z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml b/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
index 4e65004..c8c857c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_no_signal.xml
@@ -18,9 +18,8 @@
         android:width="32dp"
         android:height="32dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M2.000000,22.000000l20.000000,0.000000L22.000000,2.000000L2.000000,22.000000zM20.000000,20.000000L6.800000,20.000000L20.000000,6.800000L20.000000,20.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
index a3823ae..c510972 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_out.xml
@@ -17,8 +17,7 @@
         android:width="6.0dp"
         android:height="32dp"
         android:viewportWidth="6.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M0.000000,13.700000l3.000000,-5.700000 3.000000,5.700000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_r.xml b/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
index 2c10dc3f..40bfbe6 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_r.xml
@@ -14,11 +14,10 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8.0dp"
+        android:width="32.0dp"
         android:height="32dp"
         android:viewportWidth="6.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="6.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M2.800000,7.900000l-1.000000,0.000000L1.800000,11.000000L0.200000,11.000000L0.200000,2.500000l2.700000,0.000000c0.900000,0.000000 1.500000,0.200000 2.000000,0.700000s0.700000,1.100000 0.700000,1.900000c0.000000,0.600000 -0.100000,1.100000 -0.300000,1.500000S4.800000,7.200000 4.400000,7.400000l1.500000,3.500000L5.900000,11.000000L4.100000,11.000000L2.800000,7.900000zM1.800000,6.500000l1.100000,0.000000c0.400000,0.000000 0.600000,-0.100000 0.800000,-0.400000S4.000000,5.600000 4.000000,5.200000c0.000000,-0.400000 -0.100000,-0.800000 -0.300000,-1.000000S3.300000,3.800000 2.900000,3.800000L1.800000,3.800000L1.800000,6.500000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_vpn.xml b/packages/SystemUI/res/drawable/ic_qs_vpn.xml
index e7ef02a..cf24e12 100644
--- a/packages/SystemUI/res/drawable/ic_qs_vpn.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_vpn.xml
@@ -19,6 +19,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M12.700000,10.000000c-0.800000,-2.300000 -3.000000,-4.000000 -5.700000,-4.000000c-3.300000,0.000000 -6.000000,2.700000 -6.000000,6.000000s2.700000,6.000000 6.000000,6.000000c2.600000,0.000000 4.800000,-1.700000 5.700000,-4.000000L17.000000,14.000000l0.000000,4.000000l4.000000,0.000000l0.000000,-4.000000l2.000000,0.000000l0.000000,-4.000000L12.700000,10.000000zM7.000000,14.000000c-1.100000,0.000000 -2.000000,-0.900000 -2.000000,-2.000000c0.000000,-1.100000 0.900000,-2.000000 2.000000,-2.000000s2.000000,0.900000 2.000000,2.000000C9.000000,13.100000 8.100000,14.000000 7.000000,14.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
index fe963b1..e6f9292 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
@@ -17,8 +17,7 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
         android:fillAlpha="0.3"
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
index 82d2be2..d423ccb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
@@ -17,8 +17,7 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M13.8,13.2c-0.1,0.0 -0.3,-0.1 -0.4,-0.1c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,0.0 -0.6,-0.1 -0.9,-0.1c0.0,0.0 0.0,0.0 -0.1,0.0c0.0,0.0 0.0,0.0 0.0,0.0s0.0,0.0 0.0,0.0c0.0,0.0 0.0,0.0 -0.1,0.0c-0.3,0.0 -0.6,0.0 -0.9,0.1c-0.1,0.0 -0.3,0.0 -0.4,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.1,0.0 -0.1,0.0 -0.2,0.1c-1.6,0.5 -2.7,1.3 -2.8,1.5l5.3,6.6l0.0,0.0l0.0,0.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.700002,13.2z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
index f30ba76..1982130 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
@@ -17,8 +17,7 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M13.8,12.2l4.9,0.0c-1.0,-0.7 -3.4,-2.2 -6.7,-2.2c-4.1,0.0 -6.9,2.2 -7.2,2.5l7.2,9.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.800001,12.2z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
index 8a17083..b350111 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
@@ -17,8 +17,7 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M13.8,12.2l5.7,0.0l1.0,-1.2C20.0,10.6 16.8,8.0 12.0,8.0s-8.0,2.6 -8.5,3.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
index fcd57d0..136a004 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
@@ -17,8 +17,7 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
         android:fillColor="#FFFFFF"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
index bbff2e1..bed37b1 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
@@ -17,12 +17,11 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"/>
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
index 071892a..2dcdb71 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disconnected.xml
@@ -17,8 +17,7 @@
         android:width="26.0dp"
         android:height="24.0dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M21.0,8.5
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml
index c0e1037..1bc7438 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml
@@ -17,8 +17,7 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml
index f609295..5856115 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml
@@ -17,8 +17,7 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M13.100000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.500000,6.500000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml
index f44b303..4a5e1f8 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml
@@ -17,8 +17,7 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml
index 850f5b9..965442d 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml
@@ -17,8 +17,7 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml
index 8ccc1fd9..b29d3f9 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml
@@ -17,8 +17,7 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_no_network.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_no_network.xml
index 45cfc1c..e59e7f4 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_no_network.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_no_network.xml
@@ -17,9 +17,8 @@
         android:width="32.0dp"
         android:height="29.5dp"
         android:viewportWidth="26.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="#FFFFFFFF"
         android:pathData="M13.000000,2.000000C7.700000,2.000000 3.700000,3.900000 0.400000,6.400000L13.000000,22.000000L25.600000,6.500000C22.299999,4.000000 18.299999,2.000000 13.000000,2.000000zM13.000000,18.600000L3.300000,7.000000l0.000000,0.000000l0.000000,0.000000C6.000000,5.300000 8.700000,4.000000 13.000000,4.000000s7.000000,1.400000 9.700000,3.000000l0.000000,0.000000l0.000000,0.000000L13.000000,18.600000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_20dp.xml b/packages/SystemUI/res/drawable/ic_settings_20dp.xml
index 45ee94f..3170f86 100644
--- a/packages/SystemUI/res/drawable/ic_settings_20dp.xml
+++ b/packages/SystemUI/res/drawable/ic_settings_20dp.xml
@@ -17,8 +17,7 @@
     android:width="20dp"
     android:height="20dp"
     android:viewportWidth="24.0"
-    android:viewportHeight="24.0"
-    android:tint="?android:attr/colorControlNormal">
+    android:viewportHeight="24.0">
     <path
         android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
         android:fillColor="#ffffffff" />
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml
index 2ff0de4..09a67e1 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml
@@ -20,8 +20,7 @@
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_signal_airplane"
         android:translateX="21.9995"
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml
index 4fe585c..56ae4aa 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_airplane_disable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_airplane_disable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_signal_airplane_disable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_enable.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_enable.xml
index 9987279..b7ac0134 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_enable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_airplane_enable.xml
@@ -16,12 +16,10 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="root"
-    android:alpha="0.3"
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_signal_airplane"
         android:translateX="21.9995"
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml
index d64b199..87dfba9 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_airplane_enable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_airplane_enable_animation_root" />
-    <target
         android:name="ic_signal_airplane"
         android:animation="@anim/ic_signal_airplane_enable_animation_ic_signal_airplane" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight_disable.xml b/packages/SystemUI/res/drawable/ic_signal_flashlight_disable.xml
index 542797a..35844b7 100644
--- a/packages/SystemUI/res/drawable/ic_signal_flashlight_disable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_flashlight_disable.xml
@@ -20,8 +20,7 @@
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_signal_flashlight"
         android:translateX="21.9995"
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml
index 61e5287..e228b7c 100644
--- a/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_flashlight_disable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_flashlight_disable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_signal_flashlight_disable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight_enable.xml b/packages/SystemUI/res/drawable/ic_signal_flashlight_enable.xml
index a5ba05b..c2215f1 100644
--- a/packages/SystemUI/res/drawable/ic_signal_flashlight_enable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_flashlight_enable.xml
@@ -16,12 +16,10 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="root"
-    android:alpha="0.3"
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_signal_flashlight"
         android:translateX="21.9995"
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml
index 4bd9188..220c65e 100644
--- a/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_flashlight_enable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_flashlight_enable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_signal_flashlight_enable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_location_disable.xml b/packages/SystemUI/res/drawable/ic_signal_location_disable.xml
index e36f270..439851d 100644
--- a/packages/SystemUI/res/drawable/ic_signal_location_disable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_location_disable.xml
@@ -20,8 +20,7 @@
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_signal_location"
         android:translateX="21.9995"
diff --git a/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml
index a598b2d..0e9d1cb 100644
--- a/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_location_disable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_location_disable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_signal_location_disable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_location_enable.xml b/packages/SystemUI/res/drawable/ic_signal_location_enable.xml
index 46a72bc..d4b8673 100644
--- a/packages/SystemUI/res/drawable/ic_signal_location_enable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_location_enable.xml
@@ -16,12 +16,10 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="root"
-    android:alpha="0.3"
     android:height="48dp"
     android:width="48dp"
     android:viewportHeight="48"
-    android:viewportWidth="48"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="48" >
     <group
         android:name="ic_signal_location"
         android:translateX="21.9995"
diff --git a/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml
index 127af29..9f1d917 100644
--- a/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_location_enable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_location_enable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_signal_location_enable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
index a15a127..9c23126 100644
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_workmode_disable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_workmode_disable_animation_root" />
-    <target
         android:name="mask"
         android:animation="@anim/ic_signal_workmode_disable_animation_mask" />
     <target
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
index ad14505..f962594 100644
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_workmode_enable.xml
@@ -16,7 +16,6 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="root"
-    android:alpha="0.3"
     android:height="42dp"
     android:width="42dp"
     android:viewportHeight="42"
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
index 41d2b42..04ddfad 100644
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
@@ -17,9 +17,6 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@drawable/ic_signal_workmode_enable" >
     <target
-        android:name="root"
-        android:animation="@anim/ic_signal_workmode_enable_animation_root" />
-    <target
         android:name="ic_signal_briefcase"
         android:animation="@anim/ic_signal_workmode_enable_animation_ic_signal_briefcase" />
     <target
diff --git a/packages/SystemUI/res/drawable/minor_a_b.xml b/packages/SystemUI/res/drawable/minor_a_b.xml
index 0622aac..4bb330c 100644
--- a/packages/SystemUI/res/drawable/minor_a_b.xml
+++ b/packages/SystemUI/res/drawable/minor_a_b.xml
@@ -17,12 +17,10 @@
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="minor_a_b"
-    android:alpha="0.3"
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportHeight="8" >
     <group
         android:name="dot_02"
         android:translateX="3.25"
diff --git a/packages/SystemUI/res/drawable/minor_b_a.xml b/packages/SystemUI/res/drawable/minor_b_a.xml
index ecb4341..f61deec 100644
--- a/packages/SystemUI/res/drawable/minor_b_a.xml
+++ b/packages/SystemUI/res/drawable/minor_b_a.xml
@@ -17,12 +17,10 @@
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="minor_b_a"
-    android:alpha="0.3"
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportHeight="8" >
     <group
         android:name="dot_02"
         android:translateX="8"
diff --git a/packages/SystemUI/res/drawable/minor_b_c.xml b/packages/SystemUI/res/drawable/minor_b_c.xml
index 7f59e34..867af6d 100644
--- a/packages/SystemUI/res/drawable/minor_b_c.xml
+++ b/packages/SystemUI/res/drawable/minor_b_c.xml
@@ -17,12 +17,10 @@
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="minor_b_c"
-    android:alpha="0.3"
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportHeight="8" >
     <group
         android:name="dot_02"
         android:translateX="8"
diff --git a/packages/SystemUI/res/drawable/minor_c_b.xml b/packages/SystemUI/res/drawable/minor_c_b.xml
index 97309bc..b2e33cf 100644
--- a/packages/SystemUI/res/drawable/minor_c_b.xml
+++ b/packages/SystemUI/res/drawable/minor_c_b.xml
@@ -17,12 +17,10 @@
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:name="minor_c_b"
-    android:alpha="0.3"
     android:width="16dp"
     android:viewportWidth="16"
     android:height="8dp"
-    android:viewportHeight="8"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportHeight="8" >
     <group
         android:name="dot_02"
         android:translateX="12.75"
diff --git a/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
new file mode 100644
index 0000000..0b2bd22
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_dual_tile_caret.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
index 2ac223b..b7da30b 100644
--- a/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
+++ b/packages/SystemUI/res/drawable/qs_ic_wifi_lock.xml
@@ -17,7 +17,8 @@
     android:width="24.0dp"
     android:height="24.0dp"
     android:viewportWidth="72.0"
-    android:viewportHeight="72.0">
+    android:viewportHeight="72.0"
+    android:tint="?android:attr/textColorPrimary">
     <group
         android:translateX="52.0"
         android:translateY="42.0" >
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
similarity index 62%
rename from packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
rename to packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
index 387ca29..ea03a50 100644
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
+++ b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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,11 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
+<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"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_disable_animation.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_disable_animation.xml
index c6a2fdd..1e41a31 100644
--- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_disable_animation.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_managed_profile_disable_animation.xml
@@ -16,7 +16,6 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="27.0dp"
         android:height="22.0dp"
-        android:alpha="0.3"
         android:viewportWidth="27.0"
         android:viewportHeight="22.0">
     <clip-path
diff --git a/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml b/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml
index e85b76d..46c761a 100644
--- a/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml
+++ b/packages/SystemUI/res/layout-sw410dp/status_bar_alarm_group.xml
@@ -27,7 +27,7 @@
     <LinearLayout
         android:id="@+id/date_time_group"
         android:layout_width="wrap_content"
-        android:layout_height="19dp"
+        android:layout_height="wrap_content"
         android:orientation="horizontal"
         android:focusable="true" >
 
diff --git a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
index aaa84fd..ff55f99 100644
--- a/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
+++ b/packages/SystemUI/res/layout/qs_customize_tile_frame.xml
@@ -18,7 +18,8 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:paddingStart="8dp"
     android:paddingEnd="8dp"
-    android:paddingBottom="16dp" />
+    android:paddingTop="8dp"
+    android:gravity="center" />
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 50ee64a..25d5226 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -20,10 +20,10 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@drawable/qs_detail_background"
-    android:paddingBottom="8dp"
     android:clickable="true"
-    android:visibility="invisible"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:paddingBottom="8dp"
+    android:visibility="invisible">
 
     <com.android.systemui.ResizingSpace
         android:layout_width="match_parent"
@@ -33,17 +33,16 @@
         android:id="@+id/qs_detail_header"
         layout="@layout/qs_detail_header"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
+        android:layout_height="wrap_content"
+        />
 
     <com.android.systemui.statusbar.AlphaOptimizedImageView
         android:id="@+id/qs_detail_header_progress"
-        android:src="@drawable/indeterminate_anim"
-        android:alpha="0"
-        android:background="@color/qs_detail_progress_track"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:scaleType="fitXY"
-        android:translationY="8dp"
+        android:alpha="0"
+        android:background="@color/qs_detail_progress_track"
+        android:src="@drawable/indeterminate_anim"
         />
 
     <com.android.systemui.qs.NonInterceptingScrollView
@@ -51,12 +50,13 @@
         android:layout_height="0dp"
         android:layout_weight="1"
         android:fillViewport="true">
+
         <FrameLayout
             android:id="@android:id/content"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>
     </com.android.systemui.qs.NonInterceptingScrollView>
 
-    <include layout="@layout/qs_detail_buttons" />
+    <include layout="@layout/qs_detail_buttons"/>
 
 </com.android.systemui.qs.QSDetail>
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index 7876ada..6edf135 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -29,7 +29,8 @@
         android:layout_width="@dimen/qs_detail_item_icon_size"
         android:layout_height="@dimen/qs_detail_item_icon_size"
         android:layout_marginStart="@dimen/qs_detail_item_icon_marginStart"
-        android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd" />
+        android:layout_marginEnd="@dimen/qs_detail_item_icon_marginEnd"
+        android:tint="?android:attr/textColorPrimary"/>
 
     <LinearLayout
         android:layout_width="0dp"
@@ -62,6 +63,7 @@
         android:focusable="true"
         android:scaleType="center"
         android:contentDescription="@*android:string/media_route_controller_disconnect"
+        android:tint="?android:attr/textColorPrimary"
         android:src="@drawable/ic_qs_cancel" />
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_items.xml b/packages/SystemUI/res/layout/qs_detail_items.xml
index 9a7e1b6..b9cdf28 100644
--- a/packages/SystemUI/res/layout/qs_detail_items.xml
+++ b/packages/SystemUI/res/layout/qs_detail_items.xml
@@ -43,7 +43,8 @@
         <ImageView
             android:id="@android:id/icon"
             android:layout_width="56dp"
-            android:layout_height="56dp"/>
+            android:layout_height="56dp"
+            android:tint="?android:attr/textColorSecondary" />
 
         <TextView
             android:id="@android:id/title"
diff --git a/packages/SystemUI/res/layout/qs_page_indicator.xml b/packages/SystemUI/res/layout/qs_page_indicator.xml
new file mode 100644
index 0000000..02bd31a
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_page_indicator.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<com.android.systemui.qs.PageIndicator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/page_indicator"
+    android:layout_width="match_parent"
+    android:layout_height="48dp"
+    android:layout_gravity="center"
+    android:layout_marginTop="40dp"
+    android:layout_marginBottom="24dp"
+    android:focusable="true"
+    android:gravity="center"
+    android:importantForAccessibility="yes"
+    android:visibility="gone"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 8b6060f..8ff1d1e 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -28,15 +28,6 @@
         android:layout_height="48dp"
         android:layout_gravity="bottom">
 
-        <com.android.systemui.qs.PageIndicator
-            android:id="@+id/page_indicator"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:gravity="center"
-            android:importantForAccessibility="yes"
-            android:focusable="true" />
-
     </FrameLayout>
 
 </com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 9e0a6fe..895185b 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -26,10 +26,9 @@
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
             android:background="#0000"
-            android:layout_marginTop="80dp"
+            android:layout_marginTop="52dp"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingBottom="8dp" />
+            android:layout_height="wrap_content" />
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 5b0f0df..a093b87 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -18,11 +18,12 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:orientation="horizontal">
+        android:orientation="horizontal"
+        android:paddingTop="16dp">
      <TextView android:id="@+id/tile_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textColor="?android:attr/textColorSecondary"
+            android:textColor="?android:attr/textColorPrimary"
             android:gravity="center_horizontal"
             android:minLines="2"
             android:padding="0dp"
@@ -36,4 +37,4 @@
             android:layout_marginLeft="@dimen/restricted_padlock_pading"
             android:scaleType="centerInside"
             android:visibility="gone" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 080f553..6988c76 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -17,6 +17,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_height="48dp"
     android:layout_width="match_parent"
+    android:layout_marginBottom="24dp"
     android:paddingLeft="16dp"
     android:paddingRight="16dp"
     style="@style/BrightnessDialogContainer">
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 53acb9f..4122707 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -23,30 +23,35 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/status_bar_header_height"
     android:layout_gravity="@integer/notification_panel_layout_gravity"
-    android:clipChildren="false"
-    android:clipToPadding="false"
     android:baselineAligned="false"
     android:clickable="false"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:paddingTop="0dp"
+    android:paddingEnd="0dp"
+    android:paddingStart="0dp"
     >
 
     <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="48dp"
-        android:gravity="center"
+        android:layout_alignParentEnd="true"
         android:clipChildren="false"
         android:clipToPadding="false"
-        android:orientation="horizontal"
-        android:layout_alignParentEnd="true"
-        android:layout_marginTop="4dp"
-        android:layout_marginEnd="12dp">
+        android:gravity="center"
+        android:paddingEnd="4dp"
+        android:orientation="horizontal">
 
-        <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
+        <com.android.systemui.statusbar.phone.MultiUserSwitch
+            android:id="@+id/multi_user_switch"
             android:layout_width="48dp"
             android:layout_height="48dp"
             android:layout_alignParentEnd="true"
-            android:focusable="true"
-            android:background="@drawable/ripple_drawable" >
-            <ImageView android:id="@+id/multi_user_avatar"
+            android:background="@drawable/ripple_drawable"
+            android:focusable="true">
+
+            <ImageView
+                android:id="@+id/multi_user_avatar"
                 android:layout_width="@dimen/multi_user_avatar_expanded_size"
                 android:layout_height="@dimen/multi_user_avatar_expanded_size"
                 android:layout_gravity="center"
@@ -57,13 +62,42 @@
             android:id="@android:id/edit"
             android:layout_width="48dp"
             android:layout_height="48dp"
-            android:clipToPadding="false"
-            android:clickable="true"
-            android:focusable="true"
-            android:src="@drawable/ic_mode_edit"
             android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:clickable="true"
+            android:clipToPadding="false"
             android:contentDescription="@string/accessibility_quick_settings_edit"
-            android:padding="14dp" />
+            android:focusable="true"
+            android:padding="14dp"
+            android:src="@drawable/ic_mode_edit"
+            android:tint="?android:attr/colorForeground"/>
+
+        <LinearLayout
+            android:id="@+id/system_icons_super_container"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/status_bar_header_height"
+            android:layout_alignWithParentIfMissing="true"
+            android:layout_toStartOf="@id/multi_user_switch"
+            android:background="@drawable/ripple_drawable">
+
+            <FrameLayout
+                android:id="@+id/system_icons_container"
+                android:layout_width="wrap_content"
+                android:layout_height="24dp"
+                android:layout_gravity="center_vertical">
+
+                <include layout="@layout/system_icons" />
+            </FrameLayout>
+
+            <TextView
+                android:id="@+id/battery_level"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginStart="@dimen/header_battery_margin_expanded"
+                android:importantForAccessibility="noHideDescendants"
+                android:textColor="?android:attr/textColorPrimary"
+                android:textSize="@dimen/battery_level_text_size"/>
+        </LinearLayout>
 
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
             android:id="@+id/settings_button_container"
@@ -78,16 +112,18 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:background="@drawable/ripple_drawable"
+                android:contentDescription="@string/accessibility_quick_settings_settings"
                 android:src="@drawable/ic_settings_20dp"
-                android:contentDescription="@string/accessibility_quick_settings_settings" />
+                android:tint="?android:attr/colorForeground"/>
+
             <com.android.systemui.statusbar.AlphaOptimizedImageView
                 android:id="@+id/tuner_icon"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:paddingStart="36dp"
-                android:alpha="0.3"
-                android:visibility="invisible"
-                android:src="@drawable/tuner" />
+                android:src="@drawable/tuner"
+                android:tint="?android:attr/textColorTertiary"
+                android:visibility="invisible"/>
 
         </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
@@ -106,23 +142,26 @@
 
     <TextView
         android:id="@+id/header_emergency_calls_only"
-        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:paddingStart="16dp"
+        android:focusable="true"
+        android:gravity="center_vertical"
         android:paddingEnd="16dp"
         android:paddingTop="6dp"
-        android:visibility="gone"
-        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
-        android:text="@*android:string/emergency_calls_only"
         android:singleLine="true"
-        android:gravity="center_vertical"
-        android:focusable="true" />
+        android:text="@*android:string/emergency_calls_only"
+        android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
+        android:visibility="gone"/>
 
     <include
         android:id="@+id/date_time_alarm_group"
         layout="@layout/status_bar_alarm_group"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="16dp"
+        android:layout_marginTop="12dp"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true" />
 
@@ -130,38 +169,41 @@
         android:id="@+id/quick_qs_panel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="52dp"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="12dp"
         android:layout_alignParentEnd="true"
+        android:layout_marginTop="54dp"
+        android:layout_marginBottom="24dp"
+        android:layout_alignParentTop="true"
+        android:accessibilityTraversalAfter="@+id/date_time_group"
+        android:accessibilityTraversalBefore="@id/expand_indicator"
         android:clipChildren="false"
         android:clipToPadding="false"
-        android:importantForAccessibility="yes"
+        android:layout_marginStart="16dp"
+        android:layout_marginEnd="16dp"
         android:focusable="true"
-        android:accessibilityTraversalAfter="@+id/date_time_group"
-        android:accessibilityTraversalBefore="@id/expand_indicator" />
+        android:importantForAccessibility="yes"
+        android:paddingTop="0dp"/>
 
     <com.android.systemui.statusbar.AlphaOptimizedImageView
         android:id="@+id/qs_detail_header_progress"
-        android:src="@drawable/indeterminate_anim"
-        android:alpha="0"
-        android:background="@color/qs_detail_progress_track"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
+        android:alpha="0"
+        android:background="@color/qs_detail_progress_track"
+        android:src="@drawable/indeterminate_anim"
         />
 
     <TextView
         android:id="@+id/header_debug_info"
-        android:visibility="invisible"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:fontFamily="sans-serif-condensed"
+        android:padding="2dp"
+        android:textColor="#00A040"
         android:textSize="11dp"
         android:textStyle="bold"
-        android:textColor="#00A040"
-        android:padding="2dp"
+        android:visibility="invisible"
         />
 
 </com.android.systemui.statusbar.phone.QuickStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/recents_grid_task_view.xml b/packages/SystemUI/res/layout/recents_grid_task_view.xml
index 53bec70..1c9b9ac 100644
--- a/packages/SystemUI/res/layout/recents_grid_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_grid_task_view.xml
@@ -18,7 +18,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:focusable="true">
-    <com.android.systemui.recents.views.TaskViewThumbnail
+    <com.android.systemui.recents.views.grid.GridTaskViewThumbnail
         android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
diff --git a/packages/SystemUI/res/layout/split_clock_view.xml b/packages/SystemUI/res/layout/split_clock_view.xml
index ae5136f..8198f03 100644
--- a/packages/SystemUI/res/layout/split_clock_view.xml
+++ b/packages/SystemUI/res/layout/split_clock_view.xml
@@ -28,6 +28,7 @@
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
         android:textSize="@dimen/qs_time_collapsed_size"
+        android:textColor="?android:attr/textColorPrimary"
         />
     <TextClock
         android:id="@+id/am_pm_view"
@@ -36,6 +37,7 @@
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
         android:textSize="@dimen/qs_time_collapsed_size"
+        android:textColor="?android:attr/textColorPrimary"
         android:importantForAccessibility="no"
         />
 
@@ -44,8 +46,9 @@
         android:id="@+id/empty_time_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:visibility="invisible"
+        android:visibility="gone"
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
+        android:textColor="?android:attr/textColorPrimary"
         />
 </com.android.systemui.statusbar.policy.SplitClockView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 6784254..63af3e0 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -42,7 +42,7 @@
     <LinearLayout android:id="@+id/status_bar_contents"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:paddingStart="@dimen/status_bar_padding_start"
+        android:paddingStart="6dp"
         android:paddingEnd="8dp"
         android:orientation="horizontal"
         >
diff --git a/packages/SystemUI/res/layout/status_bar_alarm_group.xml b/packages/SystemUI/res/layout/status_bar_alarm_group.xml
index a02e9af..745320e 100644
--- a/packages/SystemUI/res/layout/status_bar_alarm_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_alarm_group.xml
@@ -41,6 +41,7 @@
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:src="@drawable/ic_access_alarms_small"
+            android:tint="?android:attr/textColorPrimary"
             android:paddingStart="6dp"
             android:gravity="center"
             android:visibility="gone" />
diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml
index ca4f727..2b4a0f5 100644
--- a/packages/SystemUI/res/layout/zen_mode_condition.xml
+++ b/packages/SystemUI/res/layout/zen_mode_condition.xml
@@ -63,6 +63,7 @@
         android:scaleType="center"
         android:layout_toStartOf="@android:id/button2"
         android:contentDescription="@string/accessibility_quick_settings_less_time"
+        android:tint="?android:attr/textColorPrimary"
         android:src="@drawable/ic_qs_minus" />
 
     <ImageView
@@ -75,6 +76,7 @@
         android:scaleType="center"
         android:layout_centerVertical="true"
         android:contentDescription="@string/accessibility_quick_settings_more_time"
+        android:tint="?android:attr/textColorPrimary"
         android:src="@drawable/ic_qs_plus" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index aa6c620..9744eb3 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Sluitskerm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Instellings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Oorsig."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Werksluitskerm"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Maak toe"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi afgeskakel."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Aandbeligting"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Geen onlangse items nie"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Jy het alles toegemaak"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Gelaai"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Ontkoppel VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Jou toestel word bestuur deur <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> gebruik <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> om jou toestel te bestuur."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Jou administrateur kan instellings, korporatiewe toegang, programme, data wat met jou toestel geassosieer word en jou toestel se ligginginligting monitor en bestuur."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Kom meer te wete"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Jy is gekoppel aan <xliff:g id="VPN_APP">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Maak VPN-instellings oop"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Jou administrateur het netwerkloglêers aangeskakel wat verkeer op jou toestel monitor.\n\nKontak jou administrateur vir meer inligting."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Jy het \'n program toestemming gegee om \'n VPN-verbinding op te stel.\n\nHierdie program kan jou toestel- en netwerkaktiwiteit monitor, insluitend e-posse, programme en webwerwe."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur.\n\nJou administrateur is in staat om jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, te monitor.\n\nKontak jou administrateur vir meer inligting.\n\nJy is ook aan \'n VPN gekoppel wat jou netwerkaktiwiteit kan monitor."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jy is gekoppel aan <xliff:g id="APPLICATION">%1$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nKontak jou administrateur vir meer inligting."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jou werkprofiel word deur <xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur. Dit is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou werknetwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Toestel sal gesluit bly totdat jy dit handmatig ontsluit"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Kry kennisgewings vinniger"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Vou uit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Vou in"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skerm is vasgespeld"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig om dit te ontspeld."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Oorsig om dit te ontspeld."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Het dit"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, dankie"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aan"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Af"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Met kragkennisgewingkontroles kan jy \'n belangrikheidvlak van 0 tot 5 vir \'n program se kennisgewings stel. \n\n"<b>"Vlak 5"</b>" \n- Wys aan die bokant van die kennisgewinglys \n- Laat volskermonderbreking toe \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 4"</b>" \n- Verhoed volskermonderbreking \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 3"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n\n"<b>"Vlak 2"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n\n"<b>"Vlak 1"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n- Versteek van sluitskerm en statusbalk \n- Wys aan die onderkant van die kennisgewinglys \n\n"<b>"Vlak 0"</b>" \n- Blokkeer alle kennisgewings van die program af"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Kennisgewings"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Jy sal nie meer hierdie kennisgewings kry nie."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-kennisgewings vir"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Laag"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Middelmatig"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hoog"</string>
+    <string name="high_importance" msgid="730741630855788381">"Dringend"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Geen klank of visuele onderbreking nie"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Wys sonder klank"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Maak geluid"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Maak geluid en spring op op skerm"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-kennisgewingkontroles"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 210647c..b3354f1 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ማያ ገጽ ቆልፍ።"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ቅንብሮች"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"አጠቃላይ እይታ።"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"የስራ ማያ ገጽ ቁልፍ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ዝጋ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>።"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi ጠፍቷል።"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"የሥራ ሁነታ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"የምሽት ብርሃን"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ሁሉንም ነገር አጽድተዋል"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"የVPN ግንኙነት አቋርጥ"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"የእርስዎ መሣሪያ በ<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ነው የሚቀናበረው።"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> የእርስዎን መሣሪያ ለማቀናበር <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ን ይጠቀማል።"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"የእርስዎ አስተዳዳሪ ከዚህ መሣሪያ ጋር የተጎዳኙ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ እና የመሣሪያዎን አካባቢ መከታተል እና ማቀናበር ይችላሉ።"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"የበለጠ ለመረዳት"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="VPN_APP">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"የVPN ቅንብሮችን ይክፈቱ"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"የእርስዎ አስተዳዳሪ የአውታረ መረብ ምዝግብ ማስታወሻ መያዝን አብርተዋል፣ ይህም በመሣሪያዎ ላይ ያለው ትራፊክ ይከታተላል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"አንድ መተግበሪያ የVPN ግንኙነት እንዲያዋቅር ፍቃድ ሰጥተውታል።\n\nይህ መተግበሪያ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የመሣሪያዎን እና የአውታረ መረብ እንቅስቃሴዎን መከታተል ይችላል።"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው የሚተዳደረው።\n\nየእርስዎ አስተዳዳሪ ቅንብሮችን፣ የኮርፖሬት መዳረሻን፣ መተግበሪያዎችን፣ ከመሣሪያዎ ጋር የተጎዳኘ ውሂብን እና የመሣሪያዎ የአካባቢ መረጃን መከታተል እና ማቀናበር ይችላል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።\n\nእንዲሁም የአውታረ መረብ ግንኙነትዎን መከታተል ከሚችል አንድ VPN ጋር ተገናኝተዋል።"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው ከ<xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nተጨማሪ መረጃ ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"የስራ መገለጫዎ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> ነው እየተዳደረ ያለው። ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የአውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝተዋል።\n\nእንዲሁም የግል አውታረ መረብ እንቅስቃሴዎን መከታተል ከሚችለው <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋርም ተገናኝተዋል።"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"እራስዎ እስኪከፍቱት ድረስ መሣሪያ እንደተቆለፈ ይቆያል"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ማሳወቂያዎችን ፈጥነው ያግኙ"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"አስፋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ሰብስብ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ማያ ገጽ ተሰክቷል"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና አጠቃላይ ዕይታ የሚለውን ይጫኑ እና ይያዙ።"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል አጠቃላይ ዕይታ ተጭነው ይያዙ።"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ገባኝ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"አይ፣ አመሰግናለሁ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ይደበቅ?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"በርቷል"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ጠፍቷል"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"በኃይል ማሳወቂያ መቆጣጠሪያዎች አማካኝነት የአንድ መተግበሪያ ማሳወቂያዎች የአስፈላጊነት ደረጃ ከ0 እስከ 5 ድረስ ማዘጋጀት ይችላሉ። \n\n"<b>"ደረጃ 5"</b>" \n- በማሳወቂያ ዝርዝሩ አናት ላይ አሳይ \n- የሙሉ ማያ ገጽ ማቋረጥን ፍቀድ \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 4"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 3"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- በፍጹም አጮልቀው አይምልከቱ \n\n"<b>"ደረጃ 2"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ እና ንዝረትን በፍጹም አይኑር \n\n"<b>"ደረጃ 1"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ ወይም ንዝረትን በፍጹም አያደርጉ \n- ከመቆለፊያ ገጽ እና የሁኔታ አሞሌ ይደብቁ \n- በማሳወቂያ ዝርዝር ግርጌ ላይ አሳይ \n\n"<b>"ደረጃ 0"</b>" \n- ሁሉንም የመተግበሪያው ማሳወቂያዎች ያግዱ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ማሳወቂያዎች"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"እነዚህን ማሳወቂያዎች ከእንግዲህ አያግኙዋቸውም።"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> ማሳወቂያዎች ለ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ዝቅተኛ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"መካከለኛ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ከፍተኛ"</string>
+    <string name="high_importance" msgid="730741630855788381">"አስቸኳይ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ምንም ድምፅ ወይም የሚታይ ትርጉም የለም"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"በፀጥታ አሳይ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ድምፅ ፍጠር"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ድምፅ ፍጠር እና በማያ ገጽ ላይ ብቅ በል"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
     <string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ማሳወቂያ ቁጥጥሮች"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ed64c41..1a92e67 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"شاشة التأمين."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"الإعدادات"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"النظرة عامة."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"شاشة تأمين بيانات العمل"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"إغلاق"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏تم إيقاف Wifi."</string>
@@ -330,6 +329,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"تحذير <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"وضع العمل"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"إضاءة ليلية"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"لقد محوتَ كل شيء"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
@@ -343,6 +348,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسيم رأسي"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"تقسيم مخصص"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"تم الشحن"</string>
@@ -423,20 +438,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"‏قطع الاتصال بشبكة VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"تتم إدارة جهازك بواسطة <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"تستخدم <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> تطبيق <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> لإدارة جهازك."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"يمكن للمشرف مراقبة الإعدادات وإدارتها والدخول إلى المؤسسة والتطبيقات والبيانات المقترنة بجهازك ومعلومات موقع الجهاز."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"مزيد من المعلومات"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"لقد اتصلت بتطبيق <xliff:g id="VPN_APP">%1$s</xliff:g>، الذي يمكن أن يراقب نشاط الشبكة، بما في ذلك رسائل البريد الإلكتروني والتطبيقات والمواقع الإلكترونية."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏فتح إعدادات الشبكة الظاهرية الخاصة (VPN)"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"شغَّل المشرف ميزة تسجيل بيانات الشبكة، والتي يتم من خلالها مراقبة حركة البيانات على جهازك.\n\nللحصول على المزيد من المعلومات، اتصل بالمشرف."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"‏لقد منحت تطبيقًا الإذن لإعداد اتصال شبكة ظاهرية خاصة (VPN).\n\nيمكن لهذا التطبيق مراقبة أنشطتك على الجهاز والشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"‏تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nبإمكان المشرف مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف.\n\nأنت متصل أيضًا بشبكة ظاهرية خاصة (VPN)، يمكنها مراقبة أنشطتك على الشبكة."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"شبكة ظاهرية خاصة"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"أنت متصل بـ <xliff:g id="APPLICATION">%1$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nللمزيد من المعلومات، اتصل بالمشرف."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"تتم إدارة ملفك الشخصي للعمل عن طريق <xliff:g id="ORGANIZATION">%1$s</xliff:g>. وهذا الملف الشخصي للعمل متصل بـ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطتك على شبكة العمل، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nأنت متصل أيضًا بـ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"سيظل الجهاز مقفلاً إلى أن يتم إلغاء قفله يدويًا"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"الحصول على الإشعارات بشكل أسرع"</string>
@@ -448,10 +467,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"توسيع"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"تصغير"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"تم تثبيت الشاشة"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"نظرة عامة\" لإزالة التثبيت."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"حسنًا"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"لا، شكرًا"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string>
@@ -518,28 +535,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"تشغيل"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"إيقاف"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"باستخدام عناصر التحكم في إشعار التشغيل، يمكنك تعيين مستوى الأهمية من 0 إلى 5 لإشعارات التطبيق. \n\n"<b>"المستوى 5"</b>" \n- العرض أعلى قائمة الإشعارات \n- يسمح بمقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 4"</b>" \n- منع مقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 3"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n\n"<b>"المستوى 2"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات واهتزاز \n\n"<b>"المستوى 1"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات أو اهتزاز أبدًا \n- الإخفاء من شاشة التأمين وشريط الحالة \n- العرض أسفل قائمة الإشعارات \n\n"<b>"المستوى 0"</b>" \n- حظر جميع الإشعارات من التطبيق"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"الإشعارات"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"لن تتلقى هذه الإشعارات بعد الآن."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"إشعارات <xliff:g id="APP">%s</xliff:g> عن"</string>
+    <string name="min_importance" msgid="7559703098688382595">"منخفض الأهمية"</string>
+    <string name="low_importance" msgid="6891335321576225228">"متوسط الأهمية"</string>
+    <string name="default_importance" msgid="6400766013567512061">"أهمية عالية"</string>
+    <string name="high_importance" msgid="730741630855788381">"عاجل"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"من دون تنبيه صوتي أو مرئي"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"عرض بدون تنبيه صوتي"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"إصدار تنبيه صوتي"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"إصدار تنبيه صوتي والظهور بسرعة على الشاشة"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
     <string name="notification_done" msgid="5279426047273930175">"تم"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"عناصر التحكم في إشعارات <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 70e768c..8950034 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ekranı kilidləyin."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ayarlar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"İcmal"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ekran kilidi"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Qapadın"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi deaktivdir."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> xəbərdarlığı"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"İş rejimi"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gecə işığı"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Son elementlər yoxdur"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hərşeyi təmizlədiniz"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Tətbiq haqqında"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Üfüqi Böl"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Şaquli Böl"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Fərdi Böl"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Dolub"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN-i bağlantıdan ayırın"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Cihaz <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> tərəfindən idarə olunur."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> istifadə edir."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administratorunuz ayarlara, korporativ girişə, tətbiqlərə, cihaz ilə əlaqədar dataya və cihazın məkan məlumatına nəzarət və idarə edə bilər."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" ("</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ətraflı məlumat"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" ("</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN Ayarlarını açın"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Admin, cihazdakı trafikə nəzarət edən şəbəkə loqlarını aktiv etdi.\n\nƏtraflı məlumat üçün admin ilə əlaqə saxlayın."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN bağlantısı quraşdırmağa icazə vermisiniz.\n\nBu tətbiq cihazınızı və şəbəkə fəaliyyətinizi, həmçinin, e-məktubları, tətbiq və veb saytları izləyə bilər."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Sizin iş profile tərəfindən idarə olunur <xliff:g id="ORGANIZATION">%1$s</xliff:g> . \n\n Sizin administrator e-poçt, apps, və web o cümlədən şəbəkə fəaliyyəti monitorinq qadirdir. \n\n Daha ətraflı məlumat üçün, administratora müraciət. \n\n Siz həmçinin şəbəkə fəaliyyətinə nəzarət edə bilərsiniz bir VPN, bağlı olduğunuz."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN (Virtual Şəxsi Şəbəkələr)"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> tətbiqinə qoşulmusunuz və o, e-məktublar, tətbiq və veb saytlar daxil olmaqla şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizə nəzarət edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir.\n\nƏtraflı məlumat üçün administratorunuz ilə əlaqə saxlayın."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə olunur. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur və iş şəbəkə fəaliyyətinizi idarə edə bilər, bura e-məktubıar, tətbiq və veb saytlar daxildir\n\nSiz, həmçinin, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə də qoşulsunuz və o, şəxsi şəbəkə fəaliyyətinizə nəzarət edə bilər."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirişləri daha sürətlə əldə edin"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişləndirin"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yığcamlaşdırın"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrana sancaq taxıldı"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri düyməsinə basıb saxlayın."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yox, çox sağ olun"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aktiv"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Deaktiv"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Enerji bildiriş nəzarəti ilə, tətbiq bildirişləri üçün əhəmiyyət səviyyəsini 0-dan 5-ə kimi ayarlaya bilərsiniz. \n\n"<b>"Səviyyə 5"</b>" \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n- Tam ekran kəsintisinə icazə verin \n- Hər zaman izləyin \n\n"<b>"Səviyyə 4"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Hər zaman izləyin \n\n"<b>"Level 3"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n\n"<b>"Level 2"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n\n"<b>"Səviyyə 1"</b>" \n- Prevent full screen interruption \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n- Ekran kilidi və ya status panelindən gizlədin \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n\n"<b>"Səviyyə 0"</b>" \n- Bütün bildirişləri tətbiqdən blok edin"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirişlər"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Bu bildirişlər daha sizə göndərilməyəcək."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> bildirişləri:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Az əhəmiyyətli"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Orta əhəmiyyətli"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Vacib"</string>
+    <string name="high_importance" msgid="730741630855788381">"Çox vacib"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Səs və ya vizual kəsintisiz"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Sakit səsli"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Səsli"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Səsli və ekranda pəncərə ilə"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildiriş nəzarəti"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 924ec8a..2313487f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključani ekran."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Podešavanja"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaključani ekran za posao"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvori"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi je isključen."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Režim rada"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svetlo"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Obrisali ste sve"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podeli horizontalno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podeli vertikalno"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođeno deljenje"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjena je"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Prekini vezu sa VPN-om"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Uređajem upravlja <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> koristi <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje uređajem."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saznajte više"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste sa aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otvorite podešavanja VPN-a"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administrator je uključio evidentiranje mreže, koje prati saobraćaj na uređaju.\n\nKontaktirajte administratora za više informacija."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Dali ste dozvolu aplikaciji da podešava VPN vezu.\n\nTa aplikacija može da nadgleda aktivnosti na uređaju i mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora.\n\nPovezani ste i na VPN, koji može da nadgleda aktivnosti na ličnoj mreži."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Brže dobijajte obaveštenja"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je zakačen"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Pregled da biste ga otkačili."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Pregled da biste ga otkačili."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Važi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li da sakrijete <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Uključeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Pomoću naprednih kontrola za obaveštenja možete da podesite nivo važnosti od 0. do 5. za obaveštenja aplikacije. \n\n"<b>"5. nivo"</b>" \n– Prikazuju se u vrhu liste obaveštenja \n- Dozvoli prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"4. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"3. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n\n"<b>"2. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n\n"<b>"1. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n– Sakrij na zaključanom ekranu i statusnoj traci \n– Prikazuju se u dnu liste obaveštenja \n\n"<b>"0. nivo"</b>" \n– Blokiraj sva obaveštenja iz aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obaveštenja"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Više nećete da dobijate ova obaveštenja."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obaveštenja aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nisko"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednje"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoko"</string>
+    <string name="high_importance" msgid="730741630855788381">"Hitno"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvučnog signala ili vizuelnog obaveštenja"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikazuje se bez zvučnog signala"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emituje se zvučni signal"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emituje se zvučni signal i prikazuje se na ekranu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obaveštenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4b9cc5a..083342a 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Экран блакіроўкі."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Налады"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Агляд."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Экран блакіроўкі дзейнасці"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрыць"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi выключаны."</string>
@@ -328,6 +327,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рэжым працы"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Начная падсветка"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Няма нядаўніх элементаў"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы ачысцілі усё"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Звесткі аб праграме"</string>
@@ -341,6 +346,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Падзяліць гарызантальна"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Падзяліць вертыкальна"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Падзяліць іншым чынам"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зараджаны"</string>
@@ -421,20 +436,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Адлучыць VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Ваша прылада знаходзіцца пад кіраваннем <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> выкарыстоўвае <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> для кіравання вашай прыладай."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Адміністратар можа маніторыць налады, карп. доступ, прагр., даныя, звяз. з прыл., і звесткі пра месцазн. прылады і кіраваць гэтым."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Даведацца больш"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Вы падключаны да праграмы <xliff:g id="VPN_APP">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" ,"</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Адкрыйце налады VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Ваш адміністратар уключыў вядзенне журнала сеткі, з дапамогай якога адсочваецца трафік на вашай прыладзе.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Вы далі праграме дазвол на наладжванне злучэння VPN.\n\nГэта праграма можа сачыць за актыўнасцю вашай прылады і вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nВаш адміністратар можа сачыць і кіраваць наладамі, доступам да карпаратыўных рэсурсаў, праграмамі, данымі, звязанымі з вашай прыладай, і звесткамі пра месцазнаходжанне прылады.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара.\n\nВы таксама падключаны да VPN, які можа сачыць за вашай сеткавай актыўнасцю."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Вы падлучаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая сачыць за вашай асабістай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Вы падключаны да праграмы <xliff:g id="APPLICATION">%1$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай дзейнасцю, уключаючы электронную пошту, праграмы і вэб-сайты."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nДля атрымання дадатковай інфармацыі звярніцеся да адміністратара."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падлучаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падлучаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Прылада будзе заставацца заблакіраванай, пакуль вы не разблакіруеце яе ўручную"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Атрымлівайце апавяшчэнні хутчэй"</string>
@@ -446,10 +465,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгарнуць"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згарнуць"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран замацаваны"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопкі \"Назад\" і \"Агляд\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопку \"Агляд\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Зразумела"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, дзякуй"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Схаваць <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +533,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Уключана"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Выключана"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"З дапамогай пашыранага кіравання апавяшчэннямі вы можаце задаваць узровень важнасці апавяшчэнняў праграмы ад 0 да 5. \n\n"<b>"Узровень 5"</b>" \n- Паказваць уверсе спіса апавяшчэнняў \n- Дазваляць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 4"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 3"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n\n"<b>"Узровень 2"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n\n"<b>"Узровень 1"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n- Хаваць з экрана блакіроўкі і панэлі стану \n- Паказваць унізе спіса апавяшчэнняў \n\n"<b>"Узровень 0"</b>" \n- Блакіраваць усе апавяшчэнні ад праграмы"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Апавяшчэнні"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Вы больш не будзеце атрымліваць гэтыя апавяшчэнні."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Апавяшчэнні праграмы <xliff:g id="APP">%s</xliff:g> для"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Нізкая важнасць"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Сярэдняя важнасць"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Высокая важнасць"</string>
+    <string name="high_importance" msgid="730741630855788381">"Тэрміновае"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без гуку ці візуальнага перапынення"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Паказваць бязгучна"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Прайграваць гук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Прайграваць гук і паказваць на экране"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Дадатковыя налады"</string>
     <string name="notification_done" msgid="5279426047273930175">"Гатова"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Элементы кантролю апавяшчэнняў <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e8b4c16..8382e38 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заключване на екрана."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Настройки"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Общ преглед."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Заключен екран на служебния профил"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Затваряне"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Функцията за Wi-Fi се изключи."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Работен режим"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нощно осветление"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Няма скорошни елементи"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Изчистихте всичко"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Вертикално разделяне"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Персонализирано разделяне"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Прекратяване на връзката с VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Устройството ви се управлява от <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> използва <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>, за да управлява устройството ви."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Администраторът ви може да набл. и управл. настройките, корпор. достъп, прилож., данните, свързани с у-вото, както и информ. за местоп. на у-вото ви."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Научете повече"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Установена е връзка с приложението <xliff:g id="VPN_APP">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, вкл. имейли, приложения и уебсайтове."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Отваряне на настройките за VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Администраторът ви е включил функцията за регистриране на мрежовата активност, която следи трафика на устройството ви.\n\nЗа повече информация се свържете с администратора си."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Разрешихте на приложение да настрои връзка с виртуална частна мрежа (VPN).\n\nТова приложение може да наблюдава активността ви на устройството и в мрежата, включително имейли, приложения и уебсайтове."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистраторът ви може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си.\n\nСъщо така е установена връзка с виртуална частна мрежа (VPN) и активността ви в нея може да се наблюдава."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава активността ви в мрежата, включително имейли, приложения и уебсайтове."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Установена е връзка с приложението <xliff:g id="APPLICATION">%1$s</xliff:g>, което може да наблюдава личната ви активност в мрежата, включително имейли, приложения и уебсайтове."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nЗа още информация се свържете с администратора си."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nУстановена е връзка и с приложението <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, което може да наблюдава личната ви активност в мрежата."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Устройството ще остане заключено, докато не го отключите ръчно"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Получавайте известия по-бързо"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгъване"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свиване"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранът е фиксиран"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за общ преглед."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Разбрах"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, благодаря"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Вкл."</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Изкл."</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"С помощта на контролите за известията можете да зададете ниво на важност от 0 до 5 за известията от дадено приложение. \n\n"<b>"Ниво 5"</b>" \n– Показване най-горе в списъка с известия. \n– Разрешаване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 4"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 3"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n\n"<b>"Ниво 2"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n\n"<b>"Ниво 1"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n– Скриване от заключения екран и лентата на състоянието. \n– Показване най-долу в списъка с известия. \n\n"<b>"Ниво 0"</b>" \n– Блокиране на всички известия от приложението."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Известия"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Вече няма да получавате тези известия."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Известия от <xliff:g id="APP">%s</xliff:g> за"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Малка"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средна"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Голяма"</string>
+    <string name="high_importance" msgid="730741630855788381">"Неотложна"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звук или визуално прекъсване"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Показване без звук"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Възпроизвеждане на звук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Възпроизвеждане на звук и показване на изскачащ прозорец на екрана"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известията от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2e543b1..f732279 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"লক স্ক্রীন।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"সেটিংস"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"এক নজরে৷"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"কর্মস্থলের স্ক্রীন লক"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"বন্ধ করুন"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi বন্ধ হয়েছে।"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"কাজের মোড"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"নাইট লাইট"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"কোনো সাম্প্রতিক আইটেম নেই"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"আপনি সবকিছু সাফ করেছেন"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"অ্যাপ্লিকেশানের তথ্য"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"চার্জ হয়েছে"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN এর সংযোগ বিচ্ছিন্ন করুন"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"আপনার ডিভাইসটি <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> এর দ্বারা পরিচালিত৷"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> আপনার ডিভাইস পরিচালনা করার জন্য <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ব্যবহার করে৷"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"আপনার প্রশাসক আপনার ডিভাইসের অবস্থান তথ্য সহ এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ্স, ডেটা নিরীক্ষণ ও পরিচালনা করতে পারেন৷"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"আরো জানুন"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"আপনি <xliff:g id="VPN_APP">%1$s</xliff:g> এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করবে৷"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN সেটিংস খুলুন"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"আপনার প্রশাসক \'নেটওয়ার্ক লগিং\' চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিক মনিটর করে৷\n\nআরো তথ্যের জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"আপনি VPN সংযোগ সেট আপ করার জন্য একটি অ্যাপ্লিকেশানকে অনুমতি দিন৷\n\nএই অ্যাপ্লিকেশানটি ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার ডিভাইস এবং নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে।"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷\n\nআপনার প্রশাসক ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে সক্ষম৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷\n\nএছাড়াও আপনি একটি VPN, এর সাথে সংযুক্ত রয়েছেন যা আপনার নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nআরো তথ্যের জন্য, আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কাজের প্রোফাইল পরিচালনা করে৷ এটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> -এ সংযুক্ত রয়েছে যা আপনার ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার কাজের নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷\n\nএছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন যা আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করতে পারে৷"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"বিজ্ঞপ্তিগুলি আরো দ্রুত পান"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"প্রসারিত করুন"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"সঙ্কুচিত করুন"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্রীন পিন করা হয়েছে"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ওভারভিউ স্পর্শ করে ধরে থাকুন৷"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"বুঝেছি"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"না থাক"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকাবেন?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"চালু আছে"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"বন্ধ আছে"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"পাওয়ার বিজ্ঞপ্তির নিয়ন্ত্রণগুলি ব্যহবার করে, আপনি কোনো অ্যাপ্লিকেশানের বিজ্ঞপ্তির জন্য ০ থেকে ৫ পর্যন্ত একটি গুরুত্বের লেভেলকে সেট করতে পারবেন৷ \n\n"<b>"লেভেল ৫"</b>" \n- বিজ্ঞপ্তি তালিকার শীর্ষে দেখায় \n- পূর্ণ স্ক্রীনের বাধাকে অনুমতি দেয় \n- সর্বদা স্ক্রীনে উপস্থিত হয় \n\n"<b>"লেভেল ৪"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- সর্বদা স্ক্রীনে উপস্থিত হয় \n\n"<b>"লেভেল ৩"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n\n"<b>"লেভেল ২"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n- কখনই শব্দ এবং কম্পন করে না \n\n"<b>"লেভেল ১"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n- কখনই শব্দ এবং কম্পন করে না \n- লক স্ক্রীন এবং স্থিতি দন্ড থেকে লুকায় \n- বিজ্ঞপ্তি তালিকার নীচের দিকে দেখায় \n\n"<b>"লেভেল ০"</b>" \n- অ্যাপ্লিকেশান থেকে সমস্ত বিজ্ঞপ্তিকে অবরূদ্ধ করে"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"বিজ্ঞপ্তি"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"আপনি আর এই বিজ্ঞপ্তিগুলি পাবেন না।"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"এর জন্য <xliff:g id="APP">%s</xliff:g> বিজ্ঞপ্তি"</string>
+    <string name="min_importance" msgid="7559703098688382595">"নিম্ন"</string>
+    <string name="low_importance" msgid="6891335321576225228">"মাঝারি"</string>
+    <string name="default_importance" msgid="6400766013567512061">"উচ্চ"</string>
+    <string name="high_importance" msgid="730741630855788381">"জরুরি"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"কোনো শব্দ বা ভিজ্যুয়াল বাধা নেই"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"নিঃশব্দে দেখান"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"শব্দ করে"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"শব্দ করে ও স্ক্রীনে ভেসে ওঠে"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
     <string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index f6dcf68..948fccd 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključan ekran."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Postavke"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaključan ekran radnog profila"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvori"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi je isključen."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Poslovni režim"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Sve ste obrisali"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Prekini VPN vezu"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vašim uređajem upravlja aplikacija <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> koristi aplikaciju <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje vašim uređajem."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Vaš administrator može pratiti postavke, korporativni pristup, aplikacije, podatke povezane s vašim uređajem i informacije o lokaciji vašeg uređaja."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saznajte više"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-poruke i web lokacije."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Postavke otvorene VPN mreže"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Vaš administrator je uključio zapisivanje na mreži, čime se prati saobraćaj na vašem uređaju.\n\nZa više informacija obratite se administratoru."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Jednoj aplikaciji ste dali odobrenje da uspostavi VPN vezu.\n\nTa aplikacija može pratiti vašu aktivnost na uređaju i mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Vašim profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može pratiti vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora.\n\nPovezani ste i na VPN, koji može pratiti vašu aktivnost na mreži."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži, uključujući e-mailove, aplikacije i web-lokacije."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste na aplikaciju <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može pratiti vaše privatne aktivnosti na mreži, uključujući e-poštu, aplikacije i web stranice."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nZa više informacija kontaktirajte svog administratora."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za posao upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Brže primaj obavještenja"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je prikačen"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <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_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>
@@ -514,28 +531,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Uključeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Uz kontrolu obavještenja o napajanju, možete postaviti nivo značaja obavještenja iz aplikacije, i to od nivoa 0 do 5. \n\n"<b>"Nivo 5"</b>" \n- Prikaži na vrhu liste obavještenja \n- Dopusti prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nvio 4"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nivo 3"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n\n"<b>"Nivo 2"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n\n"<b>"Nivo 1"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikada ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n- Sakrij sa ekrana za zaključavanje i statusne trake \n- Prikaži na dnu liste obavještenja \n\n"<b>"Nivo 0"</b>" \n- Blokiraj sva obavještenja iz aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obavještenja"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nećete više primati ova obavještenja."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obavještenje aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niska"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednja"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoka"</string>
+    <string name="high_importance" msgid="730741630855788381">"Hitno"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez ometanja zvukom ili prikazivanjem"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikaži bez zvuka"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Pusti zvuk"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Pusti zvuk i prikaži na ekranu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole <xliff:g id="APP_NAME">%1$s</xliff:g> obavještenja"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 93e9142..fd10d12 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla de bloqueig"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configuració"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visió general"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla de bloqueig per a la feina"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Tanca"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"La xarxa Wi-Fi està desactivada."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode de feina"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Llum nocturna"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"No hi ha cap element recent"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ho has esborrat tot"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desconnecta la VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> gestiona el teu dispositiu."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilitza <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> per gestionar el teu dispositiu."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"L\'administrador pot supervisar i gestionar la configuració, l\'accés corporatiu, les aplicacions, la informació d\'ubicació del dispositiu i les dades associades."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Més informació"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Estàs connectat a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Obre la configuració de la VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"L\'administrador ha activat el registre de xarxa, que supervisa el trànsit del teu dispositiu.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Has donat permís a una aplicació per configurar una connexió VPN.\n\nAquesta aplicació pot supervisar el dispositiu i l\'activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el perfil de Work.\n\nL\'administrador pot supervisar l\'activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador.\n\nA més, estàs connectat a una VPN, que pot supervisar l\'activitat a la xarxa."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estàs connectat a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nPer obtenir més informació, contacta amb l\'administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil professional. Aquest perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat professional a la xarxa, com ara els correus electrònics, les aplicacions i els llocs web.\n\nA més, estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que també pot supervisar la teva activitat personal a la xarxa."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositiu continuarà bloquejat fins que no el desbloquegis manualment."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Obtén notificacions més ràpidament"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Amplia"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Replega"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La pantalla està fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premudes les opcions Enrere i Visió general."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premuda l\'opció Visió general."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"D\'acord"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gràcies"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activat"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivat"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Amb els controls de notificació millorats, pots establir un nivell d\'importància d\'entre 0 i 5 per a les notificacions d\'una aplicació. \n\n"<b>"Nivell 5"</b>" \n- Mostra les notificacions a la part superior de la llista \n- Permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 4"</b>" \n- No permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 3"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n\n"<b>"Nivell 2"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- Les notificacions no poden emetre sons ni vibracions \n\n"<b>"Nivell 1"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- No activa mai el so ni la vibració \n- Amaga les notificacions de la pantalla de bloqueig i de la barra d\'estat \n- Mostra les notificacions a la part inferior de la llista \n\n"<b>"Nivell 0"</b>" \n- Bloqueja totes les notificacions de l\'aplicació"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacions"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ja no rebràs aquestes notificacions."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificacions de l\'aplicació <xliff:g id="APP">%s</xliff:g> per a"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Mitjana"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgent"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sense so ni interrupcions visuals"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Es mostren de manera silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Amb so"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Amb so i amb una finestra emergent"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fet"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controls de notificació de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 350db19..51fb530 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Obrazovka uzamčení"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nastavení"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Přehled"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Obrazovka uzamčení pracovního profilu"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zavřít"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Připojení Wi-Fi je vypnuto."</string>
@@ -328,6 +327,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovní režim"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noční režim"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Žádné nedávné položky"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vše je vymazáno"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
@@ -341,6 +346,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabito"</string>
@@ -421,20 +436,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Odpojit VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vaše zařízení je spravováno aplikací <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Organizace <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> používá ke správě tohoto zařízení aplikaci <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administrátor může sledovat a spravovat nastavení, firemní přístup, aplikace, data přidružená k tomuto zařízení a jeho polohu."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Další informace"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Jste připojeni k aplikaci <xliff:g id="VPN_APP">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otevřít nastavení VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administrátor zapnul protokolování sítě, které monitoruje síťový provoz v zařízení.\n\nDalší informace vám poskytne administrátor."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Udělili jste aplikaci oprávnění k nastavení připojení VPN.\n\nTato aplikace může sledovat vaši aktivitu v zařízení a v síti, včetně e-mailů, aplikací a webů."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrátor může monitorovat vaši síťovou aktivitu, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora.\n\nJste také připojeni k síti VPN, která může sledovat vaši aktivitu v síti."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Jste připojeni k aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti, včetně e-mailů, aplikací a webů."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nO další informace požádejte svého administrátora."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Zařízení zůstane uzamčeno, dokud je ručně neodemknete"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Čtěte si oznámení rychleji"</string>
@@ -446,10 +465,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbalit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sbalit"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je připnuta"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítka Přehled."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Rozumím"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, děkuji"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +533,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Zapnuto"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuto"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Rozšířené ovládací prvky oznámení umožňují nastavit úroveň důležitosti oznámení aplikace od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazit na začátku seznamu oznámení \n– Povolit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 4"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 3"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n\n"<b>"Úroveň 2"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat žádný zvukový signál ani nevibrovat \n\n"<b>"Úroveň 1"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat zvukový signál ani nevibrovat \n– Skrýt z obrazovky uzamčení a stavového řádku \n– Zobrazovat na konci seznamu oznámení \n\n"<b>";Úroveň 0"</b>" \n– Blokovat všechna oznámení z aplikace"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Oznámení"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Tato oznámení již nebudete dostávat."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Oznámení aplikace <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nízká"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Střední"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Vysoká"</string>
+    <string name="high_importance" msgid="730741630855788381">"Naléhavá"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvukového a vizuálního vyrušení"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Zobrazovat tiše"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Vydat zvukový signál"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Vydat zvukový signál a vyskočit na obrazovku"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Nastavení oznámení aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 76841dd..5c603a8 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskærm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Indstillinger"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Oversigt."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Låseskærm til arbejde"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Luk"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi er slået fra."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbejdstilstand"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattelys"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Ingen nye elementer"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har ryddet alt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Afbryd VPN-forbindelse"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Din enhed administreres af <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> bruger <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> til at administrere din enhed."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Din administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps og data, der er knyttet til denne enhed, samt enhedens placeringsoplysninger."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Få flere oplysninger"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Du har forbindelse til <xliff:g id="VPN_APP">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Åbn VPN-indstillinger"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Din administrator har aktiveret netværksregistrering, som overvåger trafik på din enhed.\n\nKontakt din administrator for at få flere oplysninger."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Du gav en app tilladelse til at konfigurere en VPN-forbindelse.\n\nDenne app kan overvåge din enhed og netværksaktivitet, bl.a. e-mails, apps og websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger.\n\nDu er også forbundet til en VPN-forbindelse, som kan overvåge din netværksaktivitet."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Udvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skærmen er fastgjort"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK, det er forstået"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tak"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Til"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Du modtager ikke længere disse underretninger."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-underretninger til"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Lav"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Middel"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Høj"</string>
+    <string name="high_importance" msgid="730741630855788381">"Haster"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ingen lyd eller pop op-visning"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Vis lydløst"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Med lyd"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Med lyd og pop op-visning"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 23f0bd0..8da6e9c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Sperrbildschirm"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Einstellungen"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Übersicht"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Sperrbildschirm für Arbeitsprofil"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Schließen"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WLAN ist deaktiviert."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Warnung für <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeitsmodus"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nachtlicht"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Keine kürzlich verwendeten Elemente"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du hast alles gelöscht"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
@@ -331,12 +336,22 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ist im abgesicherten Modus deaktiviert."</string>
-    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alle löschen"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alle schließen"</string>
     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Hierher ziehen, um den Bildschirm zu teilen"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Geteilte Schaltfläche – vertikal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Geteilte Schaltfläche – benutzerdefiniert"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Aufgeladen"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN-Verbindung trennen"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Dein Gerät wird von <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> verwaltet."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> verwaltet dein Gerät mit <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Dein Administrator kann Einstellungen, Zugriffsrechte, Apps und Daten deines Geräts und dessen Standortinformationen überwachen."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Weitere Informationen"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Du bist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden. Die VPN-App kann deine Netzwerkaktivitäten (E-Mails, Apps und Websites) erfassen."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-Einstellungen öffnen"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit wird der Verkehr auf deinem Gerät erfasst.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Du hast einer App gestattet, eine VPN-Verbindung einzurichten.\n\nDiese App kann dein Gerät und deine Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann deine Netzwerkaktivität überwachen, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du bei deinem Administrator.\n\nDu bist außerdem mit einem VPN verbunden, das deine persönliche Netzwerkaktivität überwachen kann."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du bist mit der App \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" verbunden. Diese kann deine persönlichen Netzwerkaktivitäten erfassen, einschließlich E-Mails, Apps und Websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION">%2$s</xliff:g> verbunden, die deine geschäftlichen Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit der App <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verbunden, die deine geschäftliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites.\n\nDu bist außerdem mit der App <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Das Gerät bleibt gesperrt, bis du es manuell entsperrst."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Benachrichtigungen schneller erhalten"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Maximieren"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minimieren"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Bildschirm ist fixiert"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Übersicht\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nein danke"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"An"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Aus"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Mit den erweiterten Benachrichtigungseinstellungen kannst du für App-Benachrichtigungen eine Wichtigkeitsstufe von 0 bis 5 festlegen. \n\n"<b>"Stufe 5"</b>" \n- Auf der Benachrichtigungsleiste ganz oben anzeigen \n- Vollbildunterbrechung zulassen \n- Immer kurz einblenden \n\n"<b>"Stufe 4"</b>" \n- Keine Vollbildunterbrechung \n- Immer kurz einblenden \n\n"<b>"Stufe 3"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n\n"<b>"Stufe 2"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n\n"<b>"Stufe 1"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n- Auf Sperrbildschirm und Statusleiste verbergen \n- Auf der Benachrichtigungsleiste ganz unten anzeigen \n\n"<b>"Stufe 0"</b>" \n- Alle Benachrichtigungen der App sperren"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Benachrichtigungen"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Du erhältst diese Benachrichtigungen nicht mehr."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-Benachrichtigungen für"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niedrig"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Mittel"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hoch"</string>
+    <string name="high_importance" msgid="730741630855788381">"Dringend"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Kein akustisches Signal und keine visuelle Unterbrechung"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Ohne Ton anzeigen"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Akustisches Signal"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Akustisches Signal und Bildschirmbenachrichtigung"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-Benachrichtigungseinstellungen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index a11ee0d..bc9d264 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Κλείδωμα οθόνης."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ρυθμίσεις"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Επισκόπηση."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Οθόνη κλειδωμένης εργασίας"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Κλείσιμο"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Το Wi-fi απενεργοποιήθηκε."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Λειτουργία εργασίας"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Νυχτερινός φωτισμός"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει διαγραφή όλων των στοιχείων"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Κάθετος διαχωρισμός"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Προσαρμοσμένος διαχωρισμός"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Αποσύνδεση VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Η διαχείριση της συσκευής σας γίνεται από <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> χρησιμοποιεί <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> για τη διαχείριση της συσκευής σας."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Ο διαχειριστής σας μπορεί να παρακολουθεί και να διαχειρίζεται τις ρυθμίσεις, την εταιρική πρόσβαση, τις εφαρμογές και τα δεδομένα που σχετίζονται με τη συσκευή σας, καθώς και τις πληροφορίες τοποθεσίας της συσκευής σας."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Μάθετε περισσότερα"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="VPN_APP">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Άνοιγμα Ρυθμίσεων VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Ο διαχειριστής σας έχει ενεργοποιήσει την καταγραφή δικτύου, η οποία παρακολουθεί την επισκεψιμότητα στη συσκευή σας.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με τον διαχειριστή σας."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Παραχωρήσατε σε μια εφαρμογή άδεια για τη ρύθμιση σύνδεσης VPN.\n\nΑυτή η εφαρμογή μπορεί να παρακολουθεί τη δραστηριότητα της συσκευής και του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nΟ διαχειριστής έχει τη δυνατότητα παρακολούθησης της δραστηριότητας του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με το διαχειριστή.\n\nΕπίσης, είστε συνδεδεμένοι σε VPN, το οποίο μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Έχετε συνδεθεί στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΓια περισσότερες πληροφορίες, επικοινωνήστε με το διαχειριστή."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Η διαχείριση του προφίλ εργασίας γίνεται από τον οργανισμό <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Είναι συνδεδεμένο στην εφαρμογή <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου εργασίας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστότοπων.\n\nΕπίσης, είστε συνδεδεμένοι στην εφαρμογή <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του προσωπικού σας δικτύου."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Η συσκευή θα παραμείνει κλειδωμένη έως ότου την ξεκλειδώσετε μη αυτόματα"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Λάβετε ειδοποιήσεις γρηγορότερα"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ανάπτυξη"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Σύμπτυξη"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Η οθόνη καρφιτσώθηκε"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Με αυτόν τον τρόπο παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα τα στοιχεία \"Επιστροφή\" και \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Με αυτόν τον τρόπο παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα την \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Το κατάλαβα"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Όχι"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Απόκρυψη <xliff:g id="TILE_LABEL">%1$s</xliff:g>;"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ενεργή"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Ανενεργή"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Με τα στοιχεία ελέγχου ειδοποίησης ισχύος, μπορείτε να ορίσετε ένα επίπεδο βαρύτητας από 0 έως 5 για τις ειδοποιήσεις μιας εφαρμογής. \n\n"<b>"Επίπεδο 5"</b>" \n- Εμφάνιση στην κορυφή της λίστας ειδοποιήσεων \n- Να επιτρέπεται η διακοπή πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 4"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 3"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n\n"<b>"Επίπεδο 2"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n\n"<b>"Επίπεδο 1"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n- Απόκρυψη από την οθόνη κλειδώματος και τη γραμμή κατάστασης \n- Εμφάνιση στο κάτω μέρος της λίστας ειδοποιήσεων \n\n"<b>"Επίπεδο 0"</b>" \n- Αποκλεισμός όλων των ειδοποιήσεων από την εφαρμογή"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Ειδοποιήσεις"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Δεν θα λαμβάνεται πλέον αυτές τις ειδοποιήσεις."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Ειδοποιήσεις <xliff:g id="APP">%s</xliff:g> για"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Χαμηλή"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Μεσαία"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Υψηλή"</string>
+    <string name="high_importance" msgid="730741630855788381">"Επείγον"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Χωρίς ηχητική ή οπτική διακοπή"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Εμφάνιση χωρίς ειδοποίηση"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Αναπαραγωγή ήχου"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Αναπαραγωγή ήχου και εμφάνιση στην οθόνη"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
     <string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Στοιχεία ελέγχου κοινοποίησης <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 883c812..a19ac0b 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Settings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work lock screen"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Close"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi turned off."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Your device is managed by <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uses <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> to manage your device."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Your administrator can monitor and manage settings, corporate access, apps, data associated with your device and your device\'s location information."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Find out more"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"You\'re connected to <xliff:g id="VPN_APP">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN Settings"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information contact your admin."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Get notifications faster"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 883c812..a19ac0b 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Settings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work lock screen"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Close"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi turned off."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Your device is managed by <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uses <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> to manage your device."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Your administrator can monitor and manage settings, corporate access, apps, data associated with your device and your device\'s location information."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Find out more"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"You\'re connected to <xliff:g id="VPN_APP">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN Settings"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information contact your admin."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Get notifications faster"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 883c812..a19ac0b 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Settings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work lock screen"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Close"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi turned off."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Charged"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Disconnect VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Your device is managed by <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uses <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> to manage your device."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Your administrator can monitor and manage settings, corporate access, apps, data associated with your device and your device\'s location information."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Find out more"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"You\'re connected to <xliff:g id="VPN_APP">%1$s</xliff:g>, which can monitor your network activity, including emails, apps and websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN Settings"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information contact your admin."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps and websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your network activity including emails, apps and websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"You\'re connected to <xliff:g id="APPLICATION">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps and websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nFor more information, contact your administrator."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. It is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Get notifications faster"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e20b1cae..7379347 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla bloqueada"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configuración"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Recientes"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla bloqueada del perfil de trabajo"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Cerrar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi desactivado"</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Todo borrado"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> administra tu dispositivo."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> usa <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para administrar tu dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Tu administrador puede controlar la configuración, el acceso corporativo, las apps, los datos asociados y la información de ubicación de tu dispositivo."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Más información"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Estás conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que puede controlar la actividad de tu red, incluidos los correos electrónicos, las apps y los sitios web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configuración de VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Tu administrador activó el registro de red, que controla el tráfico en tu dispositivo.\n\nComunícate con él para obtener más información."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Permitiste que una aplicación configurara una conexión VPN.\n\nEsta aplicación puede supervisar la actividad de la red y del dispositivo, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo.\n\nEl administrador puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador.\n\nTambién tienes conexión a una VPN, que puede supervisar la actividad de tu red."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red personal, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Te conectaste a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de tu red personal, incluidos los correos electrónicos, las apps y los sitios web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nPara obtener más información, comunícate con el administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo. Tiene conexión a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar la actividad de tu red de trabajo, incluidos los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién tienes conexión a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar la actividad de la red personal."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositivo permanecerá bloqueado hasta que lo desbloquees manualmente."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Recibe notificaciones más rápido"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fija"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones Atrás y Recientes."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionado el botón Recientes."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Con los controles de activación de notificaciones, puedes establecer un nivel de importancia para las notificaciones de una app. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones. \n- Permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 4"</b>" \n- No permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 3"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n\n"<b>"Nivel 2"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n\n"<b>"Nivel 1"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n- Ocultar de la pantalla bloqueada y la barra de estado. \n- Mostrar al final de la lista de notificaciones. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la app."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ya no recibirás estas notificaciones."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificaciones de <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baja"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"No emitir sonido ni mostrar"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar sin emitir sonido"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir sonido"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir sonido y mostrar en pantalla"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a2bf7a3..ea1d08f 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla de bloqueo."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ajustes"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Aplicaciones recientes."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla de bloqueo para el perfil de trabajo"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Cerrar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi desactivado."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Has rechazado todo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Tu dispositivo está administrado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utiliza <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para administrar tu dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Tu admin. puede controlar y gestionar ajustes, acceso corporativo, apps, datos asociados al dispositivo y sus datos de ubicación."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Más información"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Te has conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que puede controlar tu actividad de red, como los correos electrónicos, las aplicaciones y los sitios web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir Ajustes de red VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Tu administrador ha activado el registro de la red para controlar el tráfico en tu dispositivo.\n\nPonte en contacto con él para obtener más información."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Has concedido permiso a una aplicación para configurar una conexión VPN.\n\nEsta aplicación puede controlar tu dispositivo y tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nTu administrador puede supervisar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con tu administrador.\n\nTambién estás conectado a una red VPN que puede supervisar tu actividad de red."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estas conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar tu actividad de red personal, como correos electrónicos, aplicaciones y sitios web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que puede controlar tu actividad de red del trabajo, como correos electrónicos, aplicaciones y sitios web.\n\nPara obtener más información, ponte en contacto con el administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"El administrador de tu perfil de trabajo es <xliff:g id="ORGANIZATION">%1$s</xliff:g> y está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red, como correos electrónicos, aplicaciones y sitios web.\n\nTú también estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"El dispositivo permanecerá bloqueado hasta que se desbloquee manualmente"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Recibe notificaciones más rápido"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mostrar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ocultar"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fijada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Aplicaciones recientes."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Sí"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"No"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Los controles de energía de las notificaciones permiten establecer un nivel de importancia de 0 a 5 para las notificaciones de las aplicaciones. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones \n- Permitir interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 4"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 3"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n\n"<b>"Nivel 2"</b>" \n- Evitar interrumpir en el modo de pantalla completa\n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n\n"<b>"Nivel 1"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n- Ocultar de la pantalla de bloqueo y de la barra de estado \n- Mostrar en la parte inferior de la lista de notificaciones \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la aplicación"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ya no recibirás estas notificaciones."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificaciones de <xliff:g id="APP">%s</xliff:g>:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baja"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sin sonido ni interrupción visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir sonido"</string>
+    <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>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ed6e7f4..e6f03a1 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Kuva lukustamine."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Seaded"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ülevaade."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Töö lukustuskuva"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Sulgemine"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi on välja lülitatud."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Töörežiim"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Öövalgus"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Hiljutisi üksusi pole"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Olete kõik ära kustutanud"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikaalne poolitamine"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Kohandatud poolitamine"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Katkesta VPN-i ühendus"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Teie seadet haldab rakendus <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Organisatsioon <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> kasutab teie seadme haldamiseks rakendust <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administraator saab jälgida ja hallata teie seadmega seotud seadeid, ettevõtte juurdepääsu, rakendusi ning andmeid ja teie seadme asukohateavet."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Lisateave"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Olete ühendatud rakendusega <xliff:g id="VPN_APP">%1$s</xliff:g>, mis saab jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Ava VPN-i seaded"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Teie administraator on sisse lülitanud võrgu logimise funktsiooni, mis jälgib liiklust teie seadmes.\n\nLisateabe saamiseks pöörduge administraatori poole."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Andsite rakendusele loa VPN-i ühenduse seadistamiseks.\n\nSee rakendus võib jälgida teie seadet ja võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministraator saab jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga.\n\nTeil on ühendus ka VPN-iga, mis saab jälgida teie võrgutegevusi."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Teie seade on ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olete ühendatud rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi, sh meile, rakendusi ja veebisaite."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nLisateabe saamiseks võtke ühendust administraatoriga."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Teie tööprofiili haldab organisatsioon <xliff:g id="ORGANIZATION">%1$s</xliff:g>. See on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis võib jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nTeie seade on ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis võib jälgida teie isiklikke võrgutegevusi."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Seade jääb lukku, kuni selle käsitsi avate"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Saate märguandeid kiiremini"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laiendamine"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ahendamine"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekraan on kinnitatud"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppu Ülevaade."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selge"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Tänan, ei"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Sees"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Väljas"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Toite märguannete juhtnuppudega saate määrata rakenduse märguannete tähtsuse taseme vahemikus 0–5. \n\n"<b>"5. tase"</b>" \n- Kuva märguannete loendi ülaosas\n- Luba täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"4. tase"</b>" \n- Keela täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"3. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n\n"<b>"2. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n\n"<b>"1. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n- Peida lukustuskuval ja olekuribal \n- Kuva märguannete loendi allosas \n\n"<b>"Tase 0"</b>" \n- Blokeeri kõik rakenduse märguanded"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Märguanded"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Te ei saa enam neid märguandeid."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Rakenduse <xliff:g id="APP">%s</xliff:g> märguanded:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Väike"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Keskmine"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Suur"</string>
+    <string name="high_importance" msgid="730741630855788381">"Kiireloomuline"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Heli ja visuaalne katkestus puudub"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Kuva vaikselt"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Esita heli"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Esita heli ja tõsta märguanne esile"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtnupud"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index c8e9ade..eff5931 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantaila blokeatzeko aukera."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ezarpenak"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ikuspegi orokorra."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Laneko pantaila blokeatua"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Itxi"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi konexioa desaktibatu egin da."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Lan modua"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gaueko argia"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Ez dago azkenaldi honetako ezer"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Dena garbitu duzu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Zatitze bertikala"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Zatitze pertsonalizatua"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Deskonektatu VPN sarea"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> aplikazioak kudeatzen du gailu hau."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> erakundeak <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> erabiltzen du gailua kudeatzeko."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Gailuko ezarpenak, enpresa-sarbidea, aplikazioak eta datuak gainbegira eta kudea ditzake administratzaileak, baita gailuaren kokapen-informazioa ere."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Informazio gehiago"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Ireki VPN ezarpenak"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administratzaileak sare-erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Aplikazio bati VPN konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea.\n\nAdministratzaileak sareko jarduerak (mezu elektronikoak, aplikazioak eta webguneak barne) kontrola ditzake.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nHorrez gain, sareko jarduerak kontrola ditzakeen VPN batera konektatuta zaude."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN konexioa"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikaziora konektatuta zaude. Aplikazio horrek sarean egiten dituzun jarduera pertsonalak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> da laneko profilaren kudeatzailea, eta profila <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora konektatuta dago. Aplikazio horrek sarean egiten dituzun laneko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne.\n\nHorrez gain, sarean egiten dituzun jarduera pertsonalak kontrola ditzakeen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora konektatuta zaude."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Gailua blokeatuta egongo da eskuz desblokeatu arte"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Eskuratu jakinarazpenak azkarrago"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zabaldu"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tolestu"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantaila ainguratuta dago"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Ikuspegi orokorra\" botoia."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ados"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ez, eskerrik asko"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aktibatuta"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desaktibatuta"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Bateria-mailaren arabera jakinarazpenak kontrolatzeko aukerekin, 0 eta 5 bitarteko garrantzi-mailetan sailka ditzakezu aplikazioen jakinarazpenak. \n\n"<b>"5. maila"</b>" \n- Erakutsi jakinarazpenen zerrendaren goialdean. \n- Baimendu etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"4. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"3. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n\n"<b>"2. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n\n"<b>"1. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n- Ezkutatu pantaila blokeatutik eta egoera-barratik. \n- Erakutsi jakinarazpenen zerrendaren behealdean. \n\n"<b>"0. maila"</b>" \n- Blokeatu aplikazioaren jakinarazpen guztiak."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Jakinarazpenak"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Aurrerantzean ez duzu jasoko horrelako jakinarazpenik."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> aplikazioaren jakinarazpenak"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Txikia"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Ertaina"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Handia"</string>
+    <string name="high_importance" msgid="730741630855788381">"Premiazkoa"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ez egin soinurik eta ez erakutsi"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Erakutsi soinurik egin gabe"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Egin soinua"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Egin soinua eta erakutsi pantailan"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
     <string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1992dd6..8cba6a9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"قفل صفحه."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"تنظیمات"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"نمای کلی."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"صفحه حالت قفل نمایه کاری"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"بستن"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏Wi-Fi خاموش شد."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"حالت کار"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"نور شب"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"بدون موارد اخیر"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"همه‌چیز را پاک کرده‌اید"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسیم عمودی"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"سفارشی کردن تقسیم"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"شارژ کامل شد"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"‏قطع اتصال VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> دستگاه شما را مدیریت می‌کند."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> با استفاده از <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> دستگاهتان را مدیریت می‌کند."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"سرپرست سیستم شما می‌تواند بر تنظیمات، دسترسی شرکتی، برنامه‌ها، داده‌های مرتبط با دستگاه و اطلاعات مکان دستگاهتان نظارت داشته باشد و آن‌ها را مدیریت کند."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"بیشتر بدانید"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"به <xliff:g id="VPN_APP">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏باز کردن تنظیمات VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"سرپرست شما گزارش‌گیری شبکه را (که بر ترافیک دستگاهتان نظارت می‌کند) روشن کرده است.\n\nبرای اطلاعات بیشتر با سرپرست خود تماس بگیرید."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"‏شما به برنامه‌ای برای تنظیم اتصال VPN اجازه دادید.\n\n این برنامه می‌تواند دستگاه و فعالیت شبکه‌تان را کنترل کند، از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"‏نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود.\n\nسرپرستتان می‌تواند فعالیت شبکه‌تان از جمله رایانامه‌، برنامه‌ و وب‌‌سایت‌ها را کنترل کند.\n\nبرای دریافت اطلاعات بیشتر با سرپرستتان تماس بگیرید.\n\nهمچنین به یک VPN وصل هستید که می‌تواند فعالیت شبکه شما را کنترل کند."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"شما به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما از جمله رایانامه‌، برنامه‌ و وب‌سایت‌ها را کنترل کند."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION">%2$s</xliff:g> وصل است که فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل می‌کند.\n\nبرای دریافت اطلاعات بیشتر، با سرپرستتان تماس بگیرید."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند فعالیت شبکه کاری‌تان از جمله رایانامه، برنامه و وب‌سایت‌ها را کنترل کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت شبکه شخصی‌تان را کنترل کند."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"دستگاه قفل باقی می‌ماند تا زمانی که قفل آن را به صورت دستی باز کنید"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"دریافت سریع‌تر اعلان‌ها"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"بزرگ کردن"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"کوچک کردن"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"صفحه نمایش پین شد"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «برگشت» و «نمای کلی» را لمس کنید و نگه‌دارید."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «نمای کلی» را لمس کنید و نگه‌دارید."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"متوجه شدم"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"نه متشکرم"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> مخفی شود؟"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"روشن"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"خاموش"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"با کنترل‌های قدرتمند اعلان می‌توانید سطح اهمیت اعلان‌های هر برنامه را از ۰ تا ۵ تعیین کنید. \n\n"<b>"سطح ۵"</b>" \n- در صدر فهرست اعلان‌ها نشان داده می‌شود \n- وقفه برای نمایش تمام‌صفحه مجاز است \n- همیشه اجمالی نشان داده می‌شود \n\n"<b>"سطح ۴"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- همیشه اجمالی نشان داده می‌شود \n\n"<b>"سطح ۳"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n\n"<b>"سطح ۲"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n- هیچ‌وقت صدا و لرزش ایجاد نمی‌کند \n\n"<b>"سطح ۱"</b>" \n- نمایش تمام صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n- هیچ‌وقت صدا یا لرزش ایجاد نمی‌کند \n- در قفل صفحه و نوار وضعیت پنهان است \n- در پایین فهرست اعلان‌ها نشان داده می‌شود \n\n"<b>"سطح ۰"</b>" \n- همه اعلان‌های این برنامه مسدود است"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"اعلان‌ها"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"دیگر این اعلان‌ها را دریافت نخواهید کرد."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"اعلان‌های <xliff:g id="APP">%s</xliff:g> برای"</string>
+    <string name="min_importance" msgid="7559703098688382595">"کم"</string>
+    <string name="low_importance" msgid="6891335321576225228">"متوسط"</string>
+    <string name="default_importance" msgid="6400766013567512061">"زیاد"</string>
+    <string name="high_importance" msgid="730741630855788381">"فوری"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"بدون وقفه صوتی و تصویری"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"نمایش به‌صورت بی‌صدا"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"پخش صدا"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"پخش صدا و صفحه بازشو"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
     <string name="notification_done" msgid="5279426047273930175">"تمام"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"کنترل‌های اعلان <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7176df4..89178d6 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lukitse näyttö."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Asetukset"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Viimeisimmät."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Työlukitusnäyttö"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Sulje"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi poistettiin käytöstä."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Työtila"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Yövalo"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Ei viimeaikaisia kohteita"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Kaikki on hoidettu."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Katkaise VPN-yhteys"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Laitettasi hallinnoi <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> hallinnoi laitettasi sovelluksen <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> avulla."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Järjestelmänvalvoja voi valvoa ja hallinnoida asetuksia, yrityskäyttöä, sovelluksia, laitteen sijaintitietoja ja muita tietoja."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Lisätietoja"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Olet yhteydessä sovellukseen <xliff:g id="VPN_APP">%1$s</xliff:g>, joka voi valvoa verkkotoimintaasi, esimerkiksi sähköposteja, sovelluksia ja verkkosivustoja."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Avaa VPN-asetukset"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Järjestelmänvalvoja on ottanut käyttöön verkkolokitiedostojen tallentamisen. Sen avulla seurataan laitteellasi tapahtuvaa liikennettä.\n\nPyydä lisätietoja järjestelmänvalvojalta."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Olet myöntänyt sovellukselle oikeuden VPN-yhteyden muodostamiseen.\n\nSovellus voi valvoa laitettasi ja toimintaasi verkossa, esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJärjestelmänvalvojasi voi valvoa toimintaasi verkossa. Hän voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisätietoja saat järjestelmänvalvojaltasi.\n\nLisäksi olet muodostanut yhteyden VPN-palveluun, joka voi valvoa toimintaasi verkossa."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Olet muodostanut yhteyden sovellukseen <xliff:g id="APPLICATION">%1$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa. Sovellus voi esimerkiksi seurata avaamiasi sähköposteja, sovelluksia ja verkkosivustoja."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nSaat lisätietoja järjestelmänvalvojaltasi."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Työprofiiliasi hallinnoi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa työhön liittyvää toimintaasi verkossa. Sovellus voi seurata esimerkiksi avaamiasi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Laite pysyy lukittuna, kunnes se avataan käsin"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Näe ilmoitukset nopeammin"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laajenna."</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tiivistä."</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Näyttö on kiinnitetty"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Viimeisimmät."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selvä"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ei kiitos"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Käytössä"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Pois käytöstä"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ilmoitusten tehohallinnan avulla voit määrittää sovelluksen ilmoituksille tärkeystason väliltä 0–5. \n\n"<b>"Taso 5"</b>" \n– Ilmoitukset näytetään ilmoitusluettelon yläosassa \n– Näkyminen koko näytön tilassa sallitaan \n– Ilmoitukset kurkistavat aina näytölle\n\n"<b>"Taso 4"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ilmoitukset kurkistavat aina näytölle \n\n"<b>"Taso 3"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n\n"<b>"Taso 2"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n\n"<b>"Taso 1"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n– Ilmoitukset piilotetaan lukitusnäytöltä ja tilapalkista \n– Ilmoitukset näytetään ilmoitusluettelon alaosassa \n\n"<b>"Taso 0"</b>" \n– Kaikki sovelluksen ilmoitukset estetään"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Ilmoitukset"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Et saa näitä ilmoituksia enää."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Sovelluksen <xliff:g id="APP">%s</xliff:g> ilmoitukset:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Matala"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Keskitaso"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Korkea"</string>
+    <string name="high_importance" msgid="730741630855788381">"Kiireellinen"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ei ääntä tai näkyvää ilmoitusta"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Näkyy ilman ääntä"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ääni"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ääni, ilmoitus näkyy näytöllä"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ilmoitusten hallinta"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3ec4ecc..a26f155 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Écran de verrouillage"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Paramètres"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Aperçu"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Verrouillage de l\'écran du profil professionnel"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fermer"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi désactivé"</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Déconnecter le RPV"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Votre appareil est géré par <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilise <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> pour gérer votre appareil."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"L\'admin. de l\'entreprise peut surv. et gérer les param., l\'accès, les applis et les données de cet app., y compris sa localisation"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"En savoir plus"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Vous êtes connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>, qui peut contrôler votre activité réseau, y compris les courriels, les applications et les sites Web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Paramètres RPV ouverts"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Votre administrateur a activé la journalisation réseau, qui surveille le trafic sur votre appareil.\n\nPour en savoir plus, communiquez avec lui."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Vous avez autorisé une application à configurer une connexion RPV.\n\nCette application peut contrôler l\'activité de votre appareil et votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur.\n\nVous êtes également connecté à un RPV qui peut contrôler votre activité sur le réseau."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"RPV"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les courriels, les applications et les sites Web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nPour en savoir plus, communiquez avec votre administrateur."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris les courriels, les applications et les sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Voir les notifications plus rapidement"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 36db7dd..4090aed 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Écran de verrouillage"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Paramètres"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Aperçu"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Écran de verrouillage du profil professionnel"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fermer"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi désactivé."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Infos application"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Déconnecter le VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Votre appareil est géré par <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilise <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> pour gérer votre appareil."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Votre administrateur peut contrôler et gérer paramètres, accès aux contenus entreprise, applications, données et informations de localisation associées à cet appareil."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"En savoir plus"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Vous êtes connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>, qui peut contrôler votre activité sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Ouvrir les paramètres VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Votre administrateur a activé la journalisation réseau, qui surveille le trafic sur votre appareil.\n\nPour en savoir plus, contactez-le."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Vous avez autorisé une application à configurer une connexion VPN.\n\nCette application peut contrôler l\'activité de votre appareil et votre activité sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVotre administrateur peut contrôler votre activité sur le réseau (e-mails, applications et sites Web).\n\nPour en savoir plus, contactez votre administrateur.\n\nVous êtes également connecté à un VPN qui peut contrôler votre activité sur le réseau."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris votre activité relative aux e-mails, aux applications et aux sites Web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Vous êtes connecté à <xliff:g id="APPLICATION">%1$s</xliff:g>. Cette application peut contrôler votre activité personnelle sur le réseau, y compris les e-mails, les applications et les sites Web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nPour en savoir plus, contactez votre administrateur."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Il est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Cette application peut contrôler l\'activité de ce profil sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>. Cette application peut surveiller votre activité personnelle sur le réseau."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Recevoir les notifications plus vite"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Écran épinglé"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur les boutons Retour et Aperçu."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur le bouton Aperçu."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activé"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Désactivé"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Grâce aux commandes de gestion des notifications, vous pouvez définir le niveau d\'importance (compris entre 0 et 5) des notifications d\'une application. \n\n"<b>"Niveau 5"</b>" \n- Afficher en haut de la liste des notifications \n- Autoriser l\'interruption en plein écran \n- Toujours en aperçu \n\n"<b>"Niveau 4"</b>" \n- Empêcher l\'interruption en plein écran \n- Toujours en aperçu \n\n"<b>"Niveau 3"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n\n"<b>"Niveau 2"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n- Ne jamais émettre de signal sonore ni déclencher le vibreur \n\n"<b>"Niveau 1"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n- Ne jamais émettre de signal sonore ni déclencher le vibreur \n- Masquer les notifications dans l\'écran de verrouillage et la barre d\'état \n- Afficher au bas de la liste des notifications \n\n"<b>"Niveau 0"</b>" \n- Bloquer toutes les notifications de l\'application"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Vous ne recevrez plus ces notifications."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notifications de l\'application <xliff:g id="APP">%s</xliff:g> pour"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Faible"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Moyenne"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Élevée"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Aucune interruption sonore ni visuelle"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Affichage silencieux"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Alerte sonore"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Alerte sonore et affichage à l\'écran"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d7824e4..881d967 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla de bloqueo."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configuración"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visión xeral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla de bloqueo do perfil de traballo"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Pechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi desactivada."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de traballo"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Non hai elementos recentes"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Borraches todo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información da aplicación"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dividir en vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dividir de xeito personalizado"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"O teu dispositivo está xestionado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utiliza <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para xestionar o teu dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Para este dispositivo, o administrador pode controlar: configuración, acceso, aplicacións, datos e información de localización."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Máis información"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Estás conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configuración da VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"O administrador activou o rexistro na rede, que controla o tráfico do teu dispositivo.\n\nPara obter máis información, contacta co teu administrador."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Outorgaches permiso a unha aplicación para configurar unha conexión VPN.\n\nEsta aplicación pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO teu administrador é capaz de supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co teu administrador.\n\nTamén estás conectado a unha VPN, que pode supervisar a túa actividade na rede."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co teu administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O teu perfil de traballo está xestionado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode supervisar a túa actividade persoal na rede."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado ata que o desbloquees manualmente"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Recibir notificacións máis rápido"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ampliar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A pantalla está fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"A pantalla manterase visible ata que a soltes. Para facelo, mantén premido Atrás e Visión xeral."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"A pantalla manterase visible ata que a soltes. Para facelo, mantén premido Visión xeral."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"De acordo"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, grazas"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Queres ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activar"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivar"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Cos controis de notificacións mellorados, podes asignarlles un nivel de importancia comprendido entre 0 e 5 ás notificacións dunha aplicación determinada. \n\n"<b>"Nivel 5"</b>" \n- Mostrar na parte superior da lista de notificacións. \n- Permitir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 4"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 3"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n\n"<b>"Nivel 2"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n\n"<b>"Nivel 1"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n- Ocultar na pantalla de bloqueo e na barra de estado. \n- Mostrar na parte inferior da lista de notificacións. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas as notificacións da aplicación."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacións"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Deixarás de recibir estas notificacións."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificacións da aplicación <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urxente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Nin son nin interrupción visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar en silencio"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir son"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir son e aparecer na pantalla"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
     <string name="notification_done" msgid="5279426047273930175">"Feito"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controis de notificacións de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e86f759..1b9ea1d 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"લૉક સ્ક્રીન."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"સેટિંગ્સ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"વિહંગાવલોકન."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"કાર્ય લૉક સ્ક્રીન"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"બંધ કરો"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi બંધ કર્યું."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"કાર્ય મોડ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"રાત્રિ પ્રકાશ"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"કોઇ તાજેતરની આઇટમ્સ નથી"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"તમે બધું સાફ કર્યું"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ઍપ્લિકેશન માહિતી"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"આડું વિભક્ત કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ઊભું વિભક્ત કરો"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"કસ્ટમ વિભક્ત કરો"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ચાર્જ થઈ ગયું"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ડિસ્કનેક્ટ કરો"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"તમારું ઉપકરણ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, તમારા ઉપકરણનું સંચાલન કરવા માટે <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> નો ઉપયોગ કરે છે."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"તમારા વ્યવસ્થાપક સેટિંગ્સ, કૉર્પોરેટ ઍક્સેસ, ઍપ્સ, તમારા ઉપકરણ સાથે સંકળાયેલ ડેટા અને તમારા ઉપકરણની સ્થાન માહિતીને મૉનિટર અને સંચાલિત કરી શકે છે."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"વધુ જાણો"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"તમે <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN સેટિંગ્સ ખોલો"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કરેલ છે, જે તમારા ઉપકરણ પર ટ્રાફિકને મૉનિટર કરે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"તમે VPN કનેક્શન સેટ કરવા માટે ઍપ્લિકેશન પરવાનગી આપી.\n\nઆ ઍપ્લિકેશન ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારા ઉપકરણ અને નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે.\n\nતમારા વ્યવસ્થાપક ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરવામાં સમર્થ છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો.\n\nતમે VPN સાથે પણ કનેક્ટ છો, જે તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. તે <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ થયેલ છો, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"તમે ઉપકરણને મેન્યુઅલી અનલૉક કરશો નહીં ત્યાં સુધી તે લૉક રહેશે"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"વધુ ઝડપથી સૂચનાઓ મેળવો"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"વિસ્તૃત કરો"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"સંકુચિત કરો"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"સ્ક્રીન પિન કરેલ છે"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને વિહંગાવલોકન ટચ કરો અને પકડી રાખો."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે વિહંગાવલોકન ટચ કરો અને પકડી રાખો."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"સમજાઈ ગયું"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"નહીં આભાર"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ચાલુ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"બંધ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"પાવર સૂચના નિયંત્રણો સાથે, તમે ઍપ્લિકેશનની સૂચનાઓ માટે 0 થી 5 સુધીના મહત્વના સ્તરને સેટ કરી શકો છો. \n\n"<b>"સ્તર 5"</b>" \n- સૂચના સૂચિની ટોચ પર બતાવો \n- પૂર્ણ સ્ક્રીન અવરોધની મંજૂરી આપો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 4"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 3"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n\n"<b>"સ્તર 2"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અને વાઇબ્રેશન કરશો નહીં \n\n"<b>"સ્તર 1"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અથવા વાઇબ્રેટ કરશો નહીં \n- લૉક સ્ક્રીન અને સ્થિતિ બારથી છુપાવો \n- સૂચના સૂચિના તળિયા પર બતાવો \n\n"<b>"સ્તર 0"</b>" \n- ઍપ્લિકેશનની તમામ સૂચનાઓને અવરોધિત કરો"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"સૂચનાઓ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"તમને હવે આ સૂચનાઓ મળશે નહીં."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"આ માટે <xliff:g id="APP">%s</xliff:g> સૂચનાઓ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"નિમ્ન"</string>
+    <string name="low_importance" msgid="6891335321576225228">"મધ્યમ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ઉચ્ચ"</string>
+    <string name="high_importance" msgid="730741630855788381">"તાત્કાલિક"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"કોઈ અવાજ અથવા વિઝ્યુઅલ અવરોધ નહીં"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ચુપચાપ બતાવો"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"અવાજ કરો"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"અવાજ કરો અને સ્ક્રીન પર બતાવો"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
     <string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> સૂચના નિયંત્રણો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 13dac84..84dc2c4 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"लॉक स्क्रीन."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिंग"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"अवलोकन."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"कार्य लॉक स्‍क्रीन"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"बंद करें"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"वाई-फ़ाई को बंद किया गया."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"नाइट लाइट"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"हाल ही का कोई आइटम नहीं"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपने सब कुछ साफ़ कर दिया है"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्‍लिकेशन जानकारी"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"कस्‍टम रूप से विभाजित करें"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज हो गई है"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN डिस्‍कनेक्‍ट करें"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> आपका डिवाइस प्रबंधित करता है."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> आपका डिवाइस प्रबंधित करने के लिए <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> का उपयोग करता है."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"व्यवस्थापक डिवाइस से संबद्ध सेटिंग, कॉर्पोरेट एक्सेस, ऐप्लिकेशन, डेटा और डिवाइस की स्थान जानकारी को मॉनिटर और प्रबंधित कर सकता है."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"अधिक जानें"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"आप <xliff:g id="VPN_APP">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN सेटिंग खोलें"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"आपके व्‍यवस्‍थापक ने नेटवर्क लॉगिंग को चालू कर दिया है, जो आपके डिवाइस पर ट्रैफ़िक को मॉनीटर करती है.\n\nअधिक जानकारी के लिए अपने व्‍यवस्‍थापक से संपर्क करें."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"आपने किसी ऐप को VPN कनेक्‍शन सेट करने की अनुमति दी है.\n\nयह ऐप ईमेल, ऐप्‍स और सुरक्षित वेबसाइटों सहित आपके डिवाइस और नेटवर्क की गतिविधि की निगरानी कर सकता है."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है.\n\nआपका नियंत्रक ईमेल, ऐप्‍स और सुरक्षित वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी करने में सक्षम है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें.\n\nआप एक ऐसे VPN से भी कनेक्‍ट हैं, जो आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्‍ट है, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्‍ट हैं, जो आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"जब तक कि आप मैन्‍युअल रूप से अनलॉक नहीं करते तब तक डिवाइस लॉक रहेगा"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"सूचनाएं अधिक तेज़ी से प्राप्त करें"</string>
@@ -649,7 +668,7 @@
     <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"विवरण खोलें."</string>
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g> सेटिंग खोलें."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"सेटिंग का क्रम संपादित करें."</string>
-    <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="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>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f160f2df..8d626c8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključavanje zaslona."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Postavke"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaključan zaslon radnog profila"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvaranje"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi isključen."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način rada"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Izbrisali ste sve"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podijeli okomito"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podijeli prilagođeno"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Prekini vezu s VPN-om"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vašim uređajem upravlja aplikacija <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> upotrebljava aplikaciju <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje vašim uređajem."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administrator može nadzirati postavke, korporacijski pristup, aplikacije, podatke o uređaju i lokaciji uređaja te upravljati njima"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saznajte više"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste s aplikacijom <xliff:g id="VPN_APP">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otvorite postavke VPN-a"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administrator je uključio mrežni zapisnik koji prati promet na vašem uređaju.\n\nViše informacija možete dobiti od administratora."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Dali ste dopuštenje aplikaciji za postavljanje VPN veze.\n\nTa aplikacija može nadzirati vašu aktivnost na uređaju i mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se administratoru za više informacija.\n\nPovezani ste i s VPN-om koji može nadzirati vašu aktivnost na mreži."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nObratite se svojem administratoru za više informacija."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vašim poslovnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vašu poslovnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Primajte obavijesti brže"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširivanje"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sažimanje"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je prikvačen"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Natrag i Pregled da biste ga otkvačili."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Pregled da biste ga otkvačili."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Shvaćam"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti pločicu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Uključeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Napredne kontrole obavijesti omogućuju vam da postavite razinu važnosti za obavijesti aplikacije od 0 do 5. \n\n"<b>"Razina 5"</b>" \n– prikaži na vrhu popisa obavijesti \n– dopusti prekide prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 4"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 3"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled\n\n"<b>"Razina 2"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n\n"<b>"Razina 1"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n– ne prikazuj na zaključanom zaslonu i traci statusa \n– prikaži na dnu popisa obavijesti \n\n"<b>"Razina 0"</b>" \n– blokiraj sve obavijesti aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obavijesti"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Više nećete primati te obavijesti."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obavijesti aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niski"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednji"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoki"</string>
+    <string name="high_importance" msgid="730741630855788381">"Hitni"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvučnog ili vizualnog ometanja"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikaži tiho"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Reproduciraj zvuk"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Reproduciraj zvuk i prikaži na zaslonu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 94b0f0e..b18d594 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lezárási képernyő."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Beállítások"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Áttekintés."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Munka lezárási képernyővel"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Bezárás"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi kikapcsolva."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Munka mód"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éjszakai fény"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nincsenek mostanában használt elemek"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Mindent törölt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Osztott függőleges"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Osztott egyéni"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN-kapcsolat bontása"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Az eszközt a(z) <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> kezeli."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"A(z) <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> a(z) <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> alkalmazást használja az eszközkezeléshez."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"A rendszergazda kezelheti az eszközzel kapcsolatos beállításokat, vállalati hozzáférést, alkalmazásokat, adatokat és helyadatokat."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"További információ"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Ön kapcsolódik ehhez: <xliff:g id="VPN_APP">%1$s</xliff:g>, amely figyelheti hálózati tevékenységét, köztük a levelezést, az alkalmazás- és webhelyhasználatot."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-beállítások megnyitása"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Rendszergazdája bekapcsolta a hálózati naplózást, amely figyeli eszköze forgalmát.\n\nHa további információra van szüksége, vegye fel a kapcsolatot rendszergazdájával."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Engedélyezte egy alkalmazásnak, hogy VPN-kapcsolatot létesítsen.\n\nEz az alkalmazás (az e-mailekre, alkalmazásokra és a webhelyekre is kiterjedően) figyelemmel kísérheti az Ön eszközét és hálózati tevékenységét."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Munkaprofilját a következő felügyeli: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nA rendszergazda (az e-mailekre, alkalmazásokra és a webhelyekre is kiterjedően) figyelemmel kísérheti hálózati tevékenységét.\n\nTovábbi információért forduljon a rendszergazdához.\n\nÖn egy VPN-hez is csatlakozik, amely szintén figyelemmel kísérheti hálózati tevékenységét."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Csatlakoztatta a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazást, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ön a(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazáshoz csatlakozik, amely figyelheti személyes hálózati tevékenységét, beleértve az e-maileket, alkalmazásokat és webhelyeket."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nTovábbi információért forduljon a rendszergazdájához."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> felügyeli. Csatlakoztatva van hozzá a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazás, amely figyelheti az Ön hálózati tevékenységét, beleértve az e-maileket, az alkalmazásokat és a webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely szintén figyelemmel kísérheti személyes hálózati tevékenységét."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Az eszköz addig zárolva marad, amíg kézileg fel nem oldja"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Gyorsabban megkaphatja az értesítéseket"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kibontás"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Összecsukás"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A képernyő rögzítve van"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva az Áttekintés lehetőséget."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Értem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nem, köszönöm"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Elrejti ezt: <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Bekapcsolva"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kikapcsolva"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Az értesítési beállítások révén 0-tól 5-ig állíthatja be a fontossági szintet az alkalmazás értesítéseinél. \n\n"<b>"5. szint"</b>" \n– Megjelenítés az értesítési lista tetején \n– Teljes képernyő megszakításának engedélyezése \n– Mindig felugrik \n\n"<b>"4. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Mindig felugrik \n\n"<b>"3. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n\n"<b>"2. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés és rezgés \n\n"<b>"1. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés vagy rezgés \n– Elrejtés a lezárási képernyőről és az állapotsávról \n– Megjelenítés az értesítési lista alján \n\n"<b>"0. szint"</b>" \n– Az alkalmazás összes értesítésének letiltása"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Értesítések"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Többé nem jelennek meg ezek az értesítések."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-értesítések"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nem fontos"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Közepesen fontos"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Fontos"</string>
+    <string name="high_importance" msgid="730741630855788381">"Sürgős"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Hangjelzés és vizuális megszakítás nélkül"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Megjelenítés hangjelzés nélkül"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Hangjelzés"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Hangjelzés és felugró értesítés a képernyőn"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kész"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-értesítések vezérlői"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 8889a96..fa7cbe1 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Էկրանի կողպում:"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Կարգավորումներ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Համատեսք"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Աշխատանքային պրոֆիլի կողպէկրան"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Փակել"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>:"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi-ն անջատվեց:"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Աշխատանքային ռեժիմ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Գիշերային լույս"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Վերջին տարրեր չկան"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Դուք ջնջել եք ամենը"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Անջատել VPN-ը"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Ձեր սարքը կառավարվում է <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> հավելվածի կողմից:"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>-ը ձեր սարքը կառավարելու համար օգտագործում է <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> հավելվածը:"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Ձեր ադմինիստրատորը կարող է վերահսկել և կառավարել ձեր սարքի հետ կապակցված կարգավորումները, կորպորատիվ մուտքը, հավելվածները և տվյալները, ինչպես նաև ձեր սարքի տեղադրության տվյալները:"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Իմանալ ավելին"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Դուք կապակցված եք <xliff:g id="VPN_APP">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցային գործողությունը, այդ թվում նաև էլփոստը, հավելվածները և կայքերը:"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Բացել VPN-ի կարգավորումները"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Ձեր ադմինիստրատորը միացրել է ցանցային իրադարձությունների գրանցումը, որը վերահսկում է ձեր սարքի թրաֆիկը։\n\nԼրացուցիչ տեղեկություններ ստանալու համար դիմեք ձեր ադմինիստրատորին։"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Ինչ-որ հավելվածի թույլ եք տվել հաստատել VPN կապակցում:\n\nԱյդ հավելվածը կարող է վերահսկել ձեր սարքի և ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>:\n\nԱդմինիստրատորը կարող է վերահսկել ցանցում ունեցած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:\n\nՆաև ունեք VPN կապակցում, ինչը կարող է վերահսկել ձեր ցանցում կատարած գործողությունները:"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել ձեր ցանցի գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Դուք կապակցված եք <xliff:g id="APPLICATION">%1$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԼրացուցիչ տեղեկությունների համար դիմեք ադմինիստրատորին:"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Աշխատանքային պրոֆիլի կառավարիչն է՝ <xliff:g id="ORGANIZATION">%1$s</xliff:g>: Այն կապակցված է <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԴուք նույնպես կապակցված եք <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները:"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Ավելի արագ ստացեք ծանուցումները"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ընդարձակել"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Կոծկել"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսք կոճակը:"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Եղավ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Միացնել"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Անջատել"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ծանուցումների ընդլայնված կառավարման օգնությամբ կարող եք յուրաքանչյուր հավելվածի ծանուցումների համար նշանակել կարևորության աստիճան՝ 0-5 սահմաններում: \n\n"<b>"5-րդ աստիճան"</b>" \n- Ցուցադրել ծանուցումների ցանկի վերևում \n- Թույլատրել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"4-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"3-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n\n"<b>"2-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n\n"<b>"1-ին աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n- Չցուցադրել կողպէկրանում և կարգավիճակի գոտում \n- Ցուցադրել ծանուցումների ցանկի ներքևում \n\n"<b>"0-րդ աստիճան"</b>\n"- Արգելափակել հավելվածի բոլոր ծանուցումները"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Ծանուցումներ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Այս ծանուցումներն այլևս չեք ստանա։"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> ծանուցումներ հետևյալ ալիքի համար"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ցածր"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Միջին"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Բարձր"</string>
+    <string name="high_importance" msgid="730741630855788381">"Շտապ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Առանց ձայնի և տեսողական ընդհատումների"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Ցույց տալ անձայն"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ձայն հանել"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ձայն հանել և ցուցադրել էկրանին"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
     <string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարներ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2ccbda4..d2b7a81 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Layar kunci."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Setelan"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ringkasan."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Layar kunci kantor"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Tutup"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi dinonaktifkan."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Peringatan <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode kerja"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Cahaya Malam"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Tidak ada item baru-baru ini"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda sudah menghapus semua"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pisahkan Vertikal"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pisahkan Khusus"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Terisi"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Putuskan sambungan VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Perangkat dikelola oleh <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> menggunakan <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> untuk mengelola perangkat Anda."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Admin dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Pelajari lebih lanjut"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Buka Setelan VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat.\n\nUntuk informasi selengkapnya, hubungi admin."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Anda memberikan izin kepada aplikasi untuk menyiapkan sambungan VPN.\n\nAplikasi ini ini dapat memantau aktivitas perangkat dan jaringan, termasuk email, aplikasi, dan situs web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator.\n\nAnda juga tersambung ke VPN yang dapat memantau aktivitas jaringan."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi administrator."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g> dan tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs web.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Perangkat akan tetap terkunci hingga Anda membukanya secara manual"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Dapatkan pemberitahuan lebih cepat"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9d2d43f..28ccdf5 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lásskjár."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Stillingar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Yfirlit."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Vinnulásskjár"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Loka"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Slökkt á Wi-Fi."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Vinnustilling"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Næturljós"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Engin nýleg atriði"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Þú hefur hreinsað allt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Forritsupplýsingar"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Lóðrétt skipting"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Sérsniðin skipting"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Fullhlaðin"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Aftengja VPN-net"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Þessu tæki er stýrt af <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> notar <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> til að stýra tækinu þínu."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Kerfisstjóri getur fylgst með og stjórnað stillingum, fyrirtækjaaðgangi, forritum, gögnum tengdum tækinu og staðsetningu tækisins."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Frekari upplýsingar"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Þú ert með tengingu við <xliff:g id="VPN_APP">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Opna VPN-stillingar"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Kerfisstjóri hefur kveikt á eftirliti netkerfa, sem fylgist með netumferð á tækinu þínu.\n\nHafðu samband við kerfisstjóra til að fá frekari upplýsingar."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Þú veittir forriti heimild til að koma á VPN-tengingu.\n\nÞetta forrit getur fylgst með virkni þinni í tækinu og á netinu, þar á meðal tölvupósti, forritum og vefsvæðum."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nKerfisstjórinn þinn getur fylgst með netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar.\n\nÞú ert einnig með tengingu við VPN-net sem getur fylgst með netnotkun þinni."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nHafðu samband við kerfisstjórann til að fá frekari upplýsingar."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Vinnusniðinu þínu er stjórnað af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Það er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með vinnutengdri netnotkun þinni, þar á meðal tölvupósti, forritum og vefsvæðum.\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Tækið verður læst þar til þú opnar það handvirkt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Fáðu tilkynningar hraðar"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Stækka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minnka"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjárinn er festur"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Til baka“ og „Yfirlit“ til að losa."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Yfirlit“ til að losa."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ég skil"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei, takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fela <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Kveikt"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Slökkt"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Með orkutilkynningastýringum geturðu stillt mikilvægi frá 0 upp í 5 fyrir tilkynningar forrita. \n\n"<b>"Stig 5"</b>" \n- Sýna efst á tilkynningalista \n- Leyfa truflun þegar birt er á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 4"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 3"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n\n"<b>"Stig 2"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n\n"<b>"Stig 1"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n- Fela á lásskjá og stöðustiku \n- Sýna neðst á tilkynningalista \n\n"<b>"Stig 0"</b>" \n- Setja allar tilkynningar frá forriti á bannlista"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Tilkynningar"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Þú færð þessar tilkynningar ekki framar."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Tilkynningar frá <xliff:g id="APP">%s</xliff:g> fyrir"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ekki mikilvægt"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Í meðallagi"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Mikilvægt"</string>
+    <string name="high_importance" msgid="730741630855788381">"Áríðandi"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ekkert hljóð eða sjónræn truflun"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Sýna án hljóðs"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Spila hljóð"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Spila hljóð og birta sprettitilkynningu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 93bbd43..515f77f 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Schermata di blocco."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Impostazioni"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Panoramica."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Schermata di blocco del profilo di lavoro"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Chiudi"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi disattivato."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modalità Lavoro"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luminosità notturna"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nessun elemento recente"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hai cancellato tutto"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisione in verticale"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisione personalizzata"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Scollega VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Il dispositivo è gestito dall\'app <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utilizza l\'app <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> per gestire il dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"L\'amministratore può monitorare e gestire impostazioni, accesso aziendale, app, dati associati al dispositivo e informazioni sulla posizione del dispositivo."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ulteriori informazioni"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Sei connesso a <xliff:g id="VPN_APP">%1$s</xliff:g>, che consente di monitorare le attività di rete, inclusi siti web, email e app."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Apri impostazioni VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"L\'amministratore ha attivato i log di rete, che monitorano il traffico sul dispositivo.\n\nContatta l\'amministratore per ulteriori informazioni."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Hai autorizzato l\'app a configurare una connessione VPN.\n\nQuesta app può monitorare il tuo dispositivo e l\'attività di rete, inclusi email, app e siti web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nL\'amministratore può monitorare l\'attività di rete, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta l\'amministratore.\n\nSei connesso anche a VPN, da cui è possibile monitorare la tua attività di rete."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete, inclusi email, app e siti web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sei connesso a <xliff:g id="APPLICATION">%1$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale, inclusi email, app e siti web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Sei collegato a <xliff:g id="APPLICATION">%1$s</xliff:g>, che consente di monitorare la tua attività di rete personale, inclusi siti web, email e app."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nPer ulteriori informazioni, contatta il tuo amministratore."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g>. È connesso a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi email, app e siti web.\n\nSei connesso anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Il dispositivo resterà bloccato fino allo sblocco manuale"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Ricevi notifiche più velocemente"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Espandi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Comprimi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è bloccata"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tieni premuto Indietro e Panoramica."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tieni premuto Panoramica."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, grazie"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"On"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Off"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"I controlli di gestione delle notifiche ti consentono di impostare un livello di importanza compreso tra 0 e 5 per le notifiche di un\'app. \n\n"<b>"Livello 5"</b>" \n- Mostra in cima all\'elenco di notifiche \n- Consenti l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 4"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 3"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n\n"<b>"Livello 2"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n\n"<b>"Livello 1"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n- Nascondi da schermata di blocco e barra di stato \n- Mostra in fondo all\'elenco di notifiche \n\n"<b>"Livello 0"</b>" \n- Blocca tutte le notifiche dell\'app"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifiche"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Non riceverai più queste notifiche."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notifiche di <xliff:g id="APP">%s</xliff:g> per"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Bassa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Senza suoneria o interruzione visiva"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostra silenziosamente"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Con suoneria"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Con suoneria e visualizzazione sullo schermo"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fine"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlli di notifica per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 6b5b115..a32fbf6 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"מסך נעילה."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"הגדרות"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"סקירה."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"מסך נעילה בעבודה"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"סגור"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏Wifi כבוי."</string>
@@ -326,6 +325,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"אזהרה - <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"מצב עבודה"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"תאורת לילה"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"אין פריטים אחרונים"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"מחקת הכול"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
@@ -339,6 +344,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"פיצול אנכי"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"פיצול מותאם אישית"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"טעון"</string>
@@ -419,20 +434,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"‏נתק את ה-VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"המכשיר שלך מנוהל על ידי <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> משתמש באפליקציה <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> כדי לנהל את מכשירך."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"מנהל המערכת יכול לבצע מעקב ולנהל הגדרות, גישה ארגונית, אפליקציות ונתונים המשויכים למכשירך, ולמידע על מיקום המכשיר."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"למידע נוסף"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"אתה מחובר לאפליקציה <xliff:g id="VPN_APP">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏פתח את הגדרות ה-VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"מנהל המערכת הפעיל את תכונת רישום התנועה ברשת, אשר מנטרת את תנועת הנתונים במכשירך.\n\nלמידע נוסף, צור קשר עם מנהל המערכת."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"‏נתת לאפליקציה כלשהי הרשאה להגדיר חיבור ‏VPN‏.\n\nהאפליקציה הזו יכולה לעקוב אחר הפעילות שלך ברשת ובמכשיר, כולל הודעות אימייל, אפליקציות ואתרים."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"‏פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nמנהל המערכת שלך יכול לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך.\n\nאתה מחובר גם לרשת VPN, שיכולה לעקוב אחר הפעילות שלך ברשת."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"אתה מחובר לאפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית, כולל הודעות אימייל, אפליקציות ואתרים."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nלמידע נוסף, פנה למנהל המערכת שלך."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הוא מחובר לאפליקציה <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת העסקית, כולל הודעות אימייל, אפליקציות ואתרים.\n\nאתה מחובר גם לאפליקציה <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת הפרטית."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"המכשיר יישאר נעול עד שתבטל את נעילתו באופן ידני"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"קבל התראות מהר יותר"</string>
@@ -444,10 +463,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"הרחב"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצנים \'הקודם\' ו\'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצן \'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"הבנתי"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"לא, תודה"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +531,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"פועל"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"כבוי"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של הודעות הפעלה, תוכל להגדיר רמת חשיבות מ-0 עד 5 להודעות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצג בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתר ממסך הנעילה ומשורת הסטטוס \n- הצג בתחתית רשימת ההודעות \n\n"<b>"רמה 0"</b>" \n- חסום את כל ההודעות מהאפליקציה"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"הודעות"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"לא תקבל את ההודעות האלה יותר."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"הודעות <xliff:g id="APP">%s</xliff:g> עבור"</string>
+    <string name="min_importance" msgid="7559703098688382595">"נמוכה"</string>
+    <string name="low_importance" msgid="6891335321576225228">"בינונית"</string>
+    <string name="default_importance" msgid="6400766013567512061">"גבוהה"</string>
+    <string name="high_importance" msgid="730741630855788381">"דחופה"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ללא צליל וללא הפרעה ויזואלית"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"הצג ללא צליל"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"השמע צליל"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"השמע צליל והצג במסך"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
     <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> פקדי הודעות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index aa52801..4ac5e07 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ロック画面"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"設定"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"最近"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"仕事用プロファイルのロック画面"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"閉じる"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-FiをOFFにしました。"</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work モード"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"読書灯"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"最近のタスクはありません"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"すべてのタスクを消去しました"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"縦に分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"分割(カスタム)"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPNを切断"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"この端末は <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>で管理されています。"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> は <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>を使用してこの端末を管理しています。"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"管理者は、この端末に関連付けられた設定、コーポレート アクセス、アプリ、データと、端末の位置情報を監視および管理できます。"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"詳細"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"「<xliff:g id="VPN_APP">%1$s</xliff:g>」に接続しています。このアプリはあなたのネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN 設定を開く"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"管理者がネットワーク ログを有効にしているため、この端末のトラフィックは監視されています。\n\n詳しくは、管理者にお問い合わせください。"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"アプリにVPN接続の設定を許可しました。\n\nこのアプリはあなたの端末やネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理されています。\n\n管理者はあなたのネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。\n\nVPNにも接続しているため、VPNもネットワークアクティビティを監視できます。"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたのネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>に接続しています。このアプリはあなたの個人のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"「<xliff:g id="APPLICATION">%1$s</xliff:g>」に接続しています。このアプリはあなたの個人のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n詳しくは管理者にお問い合わせください。"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>に接続しています。このアプリはあなたの仕事のネットワークアクティビティ(メール、アプリ、ウェブサイトなど)を監視できます。\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>にも接続しているため、個人のネットワークアクティビティも監視できます。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"手動でロックを解除するまでロックされたままとなります"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"通知をすばやく確認できます"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index bb73c4b..c0b6b79 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ეკრანის დაბლოკვა."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"პარამეტრები"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"მიმოხილვა"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"სამსახურის ჩაკეტილი ეკრანი"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"დახურვა"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi გამორთულია."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> გაფრთხილება"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"სამსახურის რეჟიმი"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ღამის განათება"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ყველაფერი გასუფთავდა"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ვერტიკალური გაყოფა"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ინდივიდუალური გაყობა"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"დატენილია"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN-ის გათიშვა"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"თქვენს მოწყობილობას მართავს <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> იყენებს <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>-ს თქვენი მოწყობილობის სამართავად."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"თქვენს ადმინისტრატორს შეუძლია მოწყობილობასთან დაკავშირებული პარამეტრების, კორპორატიული წვდომის, აპებისა და მონაცემების, მათ შორის, თქვენი მოწყობილობის მდებარეობის ინფორმაციის, მონიტორინგი და მართვა."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"შეიტყვეთ მეტი"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"თქვენ დაუკავშირდით <xliff:g id="VPN_APP">%1$s</xliff:g>-ს, რომელსაც თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების, მონიტორინგი შეუძლია."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-ის პარამეტრების გახსნა"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"თქვენმა ადმინისტრატორმა ქსელის ჟურნალირება ჩართო, რომელიც თქვენი მოწყობილობის ტრაფიკის მონიტორინგს ახორციელებს.\n\nდამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"თქვენ მიეცით ნებართვა აპს, დააყენოს VPN კავშირი.\n\nამ აპს შეუძლია თქვენი მოწყობილობის და ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"თქვენს სამუშაო პროფილს მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nთქვენს ადმინისტრატორს შეუძლია თქვენი ქსელის აქტივობის მონიტორინგი, მათ შორის, ელფოსტის, აპებისა და ვებ-საიტების.\n\nდამატებითი ინფორმაციისთვის, დაუკავშირდით თქვენს ადმინისტრატორს.\n\nთქვენ ასევე დაკავშირებული ხართ VPN-თან, რომელსაც შეუძლია თქვენი ქსელის აქტივობის მონიტორინგი."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"თქვენ დაუკავშირდით <xliff:g id="APPLICATION">%1$s</xliff:g>-ს, რომელსაც თქვენი პირადი ქსელის აქტივობის მონიტორინგი შეუძლია, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nდამატებითი ინფორმაციისთვის მიმართეთ თქვენს ადმინისტრატორს."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"თქვენი სამუშაო პროფილი <xliff:g id="ORGANIZATION">%1$s</xliff:g>-ის მიერ იმართება. ის დაკავშირებულია <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი სამსახურის ქსელის აქტივობის, მათ შორის, ელფოსტის, აპებისა და ვებსაიტების მონიტორინგი.\n\nასევე, დაკავშირებული ხართ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-თან, რომელსაც შეუძლია თქვენი პირადი ქსელის აქტივობის მონიტორინგი."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"მოწყობილობის დარჩება ჩაკეტილი, სანამ ხელით არ გახსნით"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"შეტყობინებების უფრო სწრაფად მიღება"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"გავრცობა"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ჩაკეცვა"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ეკრანი ჩამაგრებულია"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „მიმოხილვა“-ს."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"გასაგებია"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"არა, გმადლობთ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ჩართული"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"გამორთული"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"შეტყობინებების მართვის საშუალებების მეშვეობით, შეგიძლიათ განსაზღვროთ აპის შეტყობინებების მნიშვნელობის დონე 0-დან 5-მდე დიაპაზონში. \n\n"<b>"დონე 5"</b>" \n— შეტყობინებათა სიის თავში ჩვენება \n— სრულეკრანიანი რეჟიმის შეფერხების დაშვება \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 4"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 3"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n\n"<b>"დონე 2"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n\n"<b>"დონე 1"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n— ჩაკეტილი ეკრანიდან და სტატუსის ზოლიდან დამალვა \n— შეტყობინებათა სიის ბოლოში ჩვენება \n\n"<b>"დონე 0"</b>" \n— აპის ყველა შეტყობინების დაბლოკვა"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"შეტყობინებები"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ამ შეტყობინებებს აღარ მიიღებთ."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-ის შეტყობინებები"</string>
+    <string name="min_importance" msgid="7559703098688382595">"დაბალი"</string>
+    <string name="low_importance" msgid="6891335321576225228">"საშუალო"</string>
+    <string name="default_importance" msgid="6400766013567512061">"მაღალი"</string>
+    <string name="high_importance" msgid="730741630855788381">"სასწრაფო"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ხმოვანი ან ვიზუალური შეფერხების გარეშე"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"უხმოდ ჩვენება"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ხმის გამოცემა"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ხმის გამოცემა და ეკრანზე გამოჩენა"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
     <string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეტყობინებების მართვის საშუალებები"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index f5bf5f5..69cd8bf 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Бекіту экраны."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Параметрлер"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Шолу."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Әрекетті құлыптау экраны"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Жабу"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi өшірілді."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Жұмыс режимі"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Түнгі жарық"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Жақындағы элементтер жоқ"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Сіз барлығын өшірдіңіз"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Қолданба туралы ақпарат"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Бөлінген тік"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Бөлінген теңшелетін"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зарядталды"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN желісін ажырату"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Құрылғыңызды <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> басқарады."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> құрылғыны <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> қолданбасымен басқарады."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Әкімші параметрлерді, корпоративтік кіру құқығын, қолданбаларды, құрылғыға қатысты деректерді, құрылғының орналасқан жер ақпаратын бақылай және басқара алады."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Толығырақ"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Желідегі әрекеттерді, соның ішінде электрондық хабарларды, қолданбаларды және вебсайттарды бақылайтын <xliff:g id="VPN_APP">%1$s</xliff:g> қолданбасына қосылдыңыз."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN параметрлерін ашу"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Әкімші құрылғыдағы трафикті қадағалау үшін желі журналын жүргізуді қосып қойған.\n\nТолығырақ ақпарат алу үшін әкімшімен хабарласыңыз."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Қолданбаға VPN байланысын орнату рұқсатын бердіңіз.\n\nБұл қолданба құрылғыңызды және желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алады."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады.\n\nӘкімші желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алады.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз.\n\nСондай-ақ сіз желідегі белсенділігіңізді бақылай алатын VPN желісіне қосылғансыз."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Сіз желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Сіз жеке желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Жеке желідегі әрекеттеріңізді, соның ішінде электрондық пошта хабарларын, қолданбаларды және вебсайттарды бақылай алатын <xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасына қосылғансыз."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол жұмыс кезінде желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасына қосылған.\n\nҚосымша ақпарат алу үшін әкімшіге хабарласыңыз."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Ол желідегі белсенділігіңізді, соның ішінде электрондық пошталарды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> қолданбасына қосылған.\n\nСондай-ақ сіз желідегі жеке белсенділігіңізді бақылай алатын <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Қолмен бекітпесін ашқанша құрылғы бекітілген күйде қалады"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Хабарландыруларды тезірек алу"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жаю"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жию"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран түйрелді"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Кері\" түймесін басып тұрыңыз."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Түсіндім"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Жоқ, рақмет"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Қосулы"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өшірулі"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Қуат хабарландыруының басқару элементтерімен қолданбаның хабарландырулары үшін 0-ден бастап 5-ке дейін маңыздылық деңгейін орнатуға болады. \n\n"<b>"5-деңгей"</b>" \n- Хабарландыру тізімінің ең басында көрсету \n- Толық экранға ашылуын рұқсат ету \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"4-деңгей"</b>" \n- Толық экранға шығармау \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"3-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n\n"<b>"2-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс және діріл шығармау \n\n"<b>"1-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс немесе діріл шығармау \n- Құлыпталған экраннан және күйін көрсету жолағынан жасыру \n- Хабарландыру тізімінің ең астында көрсету \n\n"<b>"0-деңгей"</b>" \n- Қолданбадағы барлық хабарландыруларға тыйым салу"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Хабарландырулар"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Сізге енді бұл хабарландырулар жіберілмейді."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> хабарландырулары"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Төмен"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Орташа"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Жоғары"</string>
+    <string name="high_importance" msgid="730741630855788381">"Шұғыл"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Дыбыссыз және визуалдық кедергісіз"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Дыбыссыз көрсету"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Дыбыстық сигнал беру"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Дыбыстық сигнал беру және экранға шығару"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
     <string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларды басқару элементтері"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index e160283..3b04eca 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ចាក់​សោ​អេក្រង់។"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ការកំណត់"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ទិដ្ឋភាព​។"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"អេក្រង់​ចាក់​សោ​លក្ខណៈ​ការងារ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"បិទ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"បាន​បិទ​វ៉ាយហ្វាយ។"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ការ​ព្រមាន"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"របៀបការងារ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ពន្លឺពេលយប់"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"មិនមានធាតុថ្មីៗទេ"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"អ្នកបានជម្រះអ្វីៗទាំងអស់"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មាន​កម្មវិធី"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"បំបែកបញ្ឈរ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"បំបែកផ្ទាល់ខ្លួន"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"បាន​បញ្ចូល​ថ្ម​​"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"ផ្ដាច់ VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ឧបករណ៍របស់អ្នកគ្រប់គ្រងដោយ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ។"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ប្រើប្រាស់ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ដើម្បីគ្រប់គ្រងឧបករណ៍របស់អ្នក។"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"អ្នកគ្រប់គ្រងរបស់អ្នកអាចតាមដាន និងគ្រប់គ្រងការកំណត់ ការចូលលក្ខណៈ​ក្រុមហ៊ុន កម្មវិធី ទិន្នន័យពាក់ព័ន្ធនឹងឧបករណ៍របស់អ្នក និងព័ត៌មានទីតាំងឧបករណ៍របស់អ្នក។"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ស្វែងយល់បន្ថែម"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"អ្នកបានភ្ជាប់ទៅ <xliff:g id="VPN_APP">%1$s</xliff:g> ដែលអាចតាមដានសកម្មភាពក្នុងបណ្តាញរបស់អ្នក រួមទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រផងដែរ។"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"បើក​ការ​កំណត់​ VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"អ្នក​គ្រប់គ្រង​របស់អ្នក​បាន​បើក​ការ​ធ្វើ​កំណត់ហេតុ​បណ្តាញ​ ដែល​វា​នឹង​តាមដាន​ចរាចរណ៍​បណ្តាញ​នៅលើ​ឧបករណ៍​របស់អ្នក។\n\nសម្រាប់​ព័ត៌មាន​បន្ថែម​ សូម​ទាក់ទង​អ្នក​គ្រប់គ្រង​របស់អ្នក។"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"អ្នកបានអនុញ្ញាតឲ្យកម្មវិធីដំឡើងការតភ្ជាប់ VPN។\n\nកម្មវិធីនេះអាចឃ្លាំមើលឧបករណ៍ និងសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"ប្រវត្តិការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nអ្នកគ្រប់គ្រងរបស់អ្នកមានលទ្ធភាពអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រួមបញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក។\n\nអ្នកក៏ត្រូវបានភ្ជាប់ជាមួួយ VPN ផងដែរ ដែលវាអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក។"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"អ្នកត្រូវបានតភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"អ្នកត្រូវបានភ្ជាប់ទៅ <xliff:g id="APPLICATION">%1$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី និងគេហទំព័រ។"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nសម្រាប់ព័ត៌មានបន្ថែម សូមទាក់ទងអ្នកគ្រប់គ្រប់របស់អ្នក។"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ប្រវត្តិរូបការងាររបស់អ្នកត្រូវបានគ្រប់គ្រងដោយ <xliff:g id="ORGANIZATION">%1$s</xliff:g>។ វាត្រូវបានតភ្ជាប់ទៅនឹង <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញរបស់អ្នក រាប់បញ្ចូលទាំងអ៊ីមែល កម្មវិធី គេហទំព័រ។\n\nអ្នកក៏ត្រូវបានតភ្ជាប់ផងដែរទៅនឹង <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ដែលអាចឃ្លាំមើលសកម្មភាពបណ្តាញផ្ទាល់ខ្លួនរបស់អ្នក។"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ឧបករណ៍​នឹង​ចាក់​សោ​រហូត​ដល់​អ្នក​ដោះ​សោ​ដោយ​ដៃ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ទទួល​បាន​ការ​ជូន​ដំណឹង​កាន់តែ​លឿន"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ពង្រីក"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"បង្រួម"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"អេក្រង់​ត្រូវ​បាន​ភ្ជាប់"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​សង្កត់​ប៊ូតុង​ថយ​ក្រោយ និង​ប៊ូតុង​ទិដ្ឋភាពរួម​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការ​ដៅ។ សូម​សង្កត់​ប៊ូតុង​ទិដ្ឋភាពរួម​​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"យល់​ហើយ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ទេ អរគុណ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"បើក"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"បិទ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ជាមួយអង្គគ្រប់គ្រងការជូនដំណឹងថាមពល អ្នកអាចកំណត់កម្រិតសំខាន់ពី 0 ទៅ 5 សម្រាប់ការជូនដំណឹងរបស់កម្មវិធី។ \n\n"<b>"កម្រិត 5"</b>" \n- បង្ហាញនៅផ្នែកខាងលើបញ្ជីជូនដំណឹង \n- អនុញ្ញាតការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 4"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 3"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 2"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n\n"<b>"កម្រិត 1"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n- លាក់ពីអេក្រង់ចាក់សោ និងរបារស្ថានភាព \n- បង្ហាញនៅផ្នែកខាងក្រោមបញ្ជីជូនដំណឹង \n\n"<b>"កម្រិត 0"</b>" \n- រារាំងការជូនដំណឹងទាំងអស់ពីកម្មវិធី"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ការ​ជូនដំណឹង"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"អ្នក​នឹង​មិន​ទទួល​បាន​ការ​ជូនដំណឹង​ទាំងនេះ​ទៀត​ទេ។"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ការ​ជូន​ដំណឹង​របស់ <xliff:g id="APP">%s</xliff:g> សម្រាប់"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ទាប"</string>
+    <string name="low_importance" msgid="6891335321576225228">"មធ្យម"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ខ្ពស់"</string>
+    <string name="high_importance" msgid="730741630855788381">"បន្ទាន់"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"គ្មាន​សំឡេង ឬ​ការរំខាន​ដល់​ការ​មើល​ឡើយ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"បង្ហាញ​ស្ងាត់ៗ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"បន្លឺ​សំឡេង"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"បន្លឺ​សំឡេង និង​លេច​ឡើង​នៅ​លើ​អេក្រង់"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
     <string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"អង្គគ្រប់គ្រងការជូនដំណឹង <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 4073cc4..e26ac87 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ಲಾಕ್‌ ಪರದೆ."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ಸಮಗ್ರ ನೋಟ."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ಮುಚ್ಚು"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ವೈಫೈ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ಕೆಲಸದ ಮೋಡ್"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ನೈಟ್ ಲೈಟ್"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ನೀವು ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿರುವಿರಿ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ಸಂಪರ್ಕಕಡಿತಗೊಳಿಸಿ"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ನಿಮ್ಮ ಸಾಧನವನ್ನು <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ನಿಂದ ನಿರ್ವಹಿಸಲಾಗಿದೆ."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸಲು <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ಅನ್ನು ಬಳಸುತ್ತದೆ."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳ ಮಾಹಿತಿಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ, <xliff:g id="VPN_APP">%1$s</xliff:g> ಗೆ ನೀವು ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಟ್ರಾಫಿಕ್ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಲು ನೆಟ್‌ವರ್ಕ್ ಲಾಗಿನ್ ಮಾಡುವಿಕೆಯನ್ನು ಆನ್ ಮಾಡಿದ್ದಾರೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"ನೀವು VPN ಸಂಪರ್ಕ ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡಿರುವಿರಿ.\n\nಈ ಅಪ್ಲಿಕೇಶನ್ ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"ನಿಮ್ಮ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡುವ ಸಾಮರ್ಥ್ಯವನ್ನು ಹೊಂದಿದ್ದಾರೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.\n\nನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ VPN ಗೆ ಕೂಡಾ ನೀವು ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ. ಇದು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು, ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿದೆ.\n\nನೀವು ಕೂಡಾ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರುವಿರಿ."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ನೀವಾಗಿಯೇ ಅನ್‌ಲಾಕ್‌ ಮಾಡುವವರೆಗೆ ಸಾಧನವು ಲಾಕ್‌ ಆಗಿಯೇ ಇರುತ್ತದೆ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ವೇಗವಾಗಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ವಿಸ್ತರಿಸು"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ಸಂಕುಚಿಸು"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ಪರದೆಯನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ತಿಳಿಯಿತು"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ಧನ್ಯವಾದಗಳು"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ಆನ್"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ಆಫ್"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ಪವರ್ ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳ ಮೂಲಕ, ನೀವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಅಧಿಸೂಚನೆಗಳನ್ನು 0 ರಿಂದ 5 ರವರೆಗಿನ ಹಂತಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಬಹುದು. \n\n"<b>"ಹಂತ 5"</b>" \n- ಮೇಲಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ಅನುಮತಿಸಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ \n\n"<b>"ಹಂತ 4"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ\n\n"<b>"ಹಂತ 3"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n\n"<b>"ಹಂತ 2"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n\n"<b>"ಹಂತ 1"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n- ಸ್ಥಿತಿ ಪಟ್ಟಿ ಮತ್ತು ಲಾಕ್ ಪರದೆಯಿಂದ ಮರೆಮಾಡಿ \n- ಕೆಳಗಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n\n"<b>"ಹಂತ 0"</b>" \n- ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ನೀವು ಇನ್ನು ಮುಂದೆ ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆಯುವುದಿಲ್ಲ."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ಇದಕ್ಕೆ <xliff:g id="APP">%s</xliff:g> ಅಧಿಸೂಚನೆಗಳಿಗೆ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ಕಡಿಮೆ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ಮಧ್ಯಮ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ಅಧಿಕ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ತುರ್ತು"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ದೃಶ್ಯ ಅಡಚಣೆಗಳಿಲ್ಲ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ಮೌನವಾಗಿ ತೋರಿಸಿ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ಧ್ವನಿ ಮಾಡಿ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ಪರದೆಯ ಮೇಲೆ ಧ್ವನಿಮಾಡಿ ಮತ್ತು ಪಾಪ್ ಮಾಡಿ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index abea176..62b5d47 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"화면을 잠급니다."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"설정"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"최근 사용"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"업무용 잠금 화면"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"닫기"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi가 사용 중지되었습니다."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"작업 모드"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"야간 조명"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"최근 항목이 없습니다."</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"모든 항목을 삭제했습니다."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"수직 분할"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"맞춤 분할"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN 연결 해제"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>에서 관리하는 기기입니다."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>이(가) <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>을(를) 사용하여 내 기기를 관리합니다."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"관리자는 설정, 기업 액세스, 앱, 기기 관련 데이터 및 기기의 위치 정보를 모니터링하고 관리할 수 있습니다."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"자세히 알아보기"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"공개 VPN 설정"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"관리자가 기기 트래픽을 모니터링하는 네트워크 로깅을 사용 설정했습니다.\n\n자세한 정보는 관리자에게 문의하세요."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN 연결을 설정할 수 있는 권한을 앱에 부여했습니다.\n\n이 앱에서 이메일, 앱, 웹사이트와 같은 내 네트워크 활동 및 기기를 모니터링할 수 있습니다."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다.\n\n관리자는 이메일, 앱, 웹사이트와 같은 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요.\n\n또한 VPN에 연결되어 있으며 여기에서 내 네트워크 활동을 모니터링할 수 있습니다."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용은 관리자에게 문의하세요."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이는 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 있으며 여기에서 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n또한 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에 연결되어 있으며, 여기에서 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"수동으로 잠금 해제할 때까지 기기가 잠금 상태로 유지됩니다."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"알림을 더욱 빠르게 받기"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"펼치기"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"접기"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"화면 고정됨"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치하세요."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"확인"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"거부"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"사용"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"사용 안함"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"전원 알림 컨트롤을 사용하면 앱 알림 관련 중요도를 0부터 5까지로 설정할 수 있습니다. \n\n"<b>"레벨 5"</b>" \n- 알림 목록 상단에 표시 \n- 전체 화면일 경우 알림 표시 허용 \n- 항상 엿보기 표시 \n\n"<b>"레벨 4"</b>" \n- 전체 화면에 알림 표시 금지 \n- 항상 엿보기 표시 \n\n"<b>"레벨 3"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n\n"<b>"레벨 2"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n\n"<b>"레벨 1"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n- 잠금 화면 및 상태 표시줄에서 숨김 \n- 알림 목록 하단에 표시 \n\n"<b>"레벨 0"</b>" \n- 앱의 모든 알림 차단"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"알림"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"더 이상 다음의 알림을 받지 않습니다."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"다음 채널의 <xliff:g id="APP">%s</xliff:g> 알림"</string>
+    <string name="min_importance" msgid="7559703098688382595">"낮음"</string>
+    <string name="low_importance" msgid="6891335321576225228">"중간"</string>
+    <string name="default_importance" msgid="6400766013567512061">"높음"</string>
+    <string name="high_importance" msgid="730741630855788381">"긴급"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"소리나 시각적인 방해 없음"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"조용히 표시"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"소리로 알림"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"소리 및 화면 표시로 알림"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
     <string name="notification_done" msgid="5279426047273930175">"완료"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 관리"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 804511a..2dc5c1d 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Кулпуланган экран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Жөндөөлөр"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Көз жүгүртүү."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Жумуштун кулпуланган экраны"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Жабуу"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi өчүрүлдү."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Иштөө режими"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Түнкү жарык"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Акыркы колдонмолор жок"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Баарын тазаладыңыз"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Колдонмо жөнүндө маалымат"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Кубатталды"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN\'ди ажыратуу"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Түзмөгүңүз <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> тарабынан башкарылат."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Түзмөгүңүздү башкаруу үчүн <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> уюму <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> колдонмосун колдонот."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Администраторуңуз жөндөөлөрдү, корпоративдик кирүү мүмкүнчүлүгүн, колдонмолорду, уруксаттарды жана ушул түзмөкө байланыштуу дайындарды, ошондой эле түзмөгүңүздүн жайгашкан жери тууралуу маалыматты көзөмөлдөп жана башкара алат."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Кеңири маалымат"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тескей турган <xliff:g id="VPN_APP">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN жөндөөлөрүн ачуу"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Администраторуңуз тармактын таржымалын алууну иштетти, андыктан түзмөгүңүздөгү трафик көзөмөлгө алынды.\n\nКеңири маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Колдонмого VPN туташуусун орнотууга уруксат бердиңиз.\n\nБул колдонмо түзмөгүңүздү жана электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди көзөмөлдөй алат."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат.\n\nАдминистраторуңуз электрондук почталар, колдонмолор жана вебсайттар сыяктуу тармактагы аракеттериңизди тескей алат.\n\nКөбүрөөк маалымат алуу үчүн, администраторуңузга кайрылыңыз.\n\nМындан тышкары, тармактагы аракеттериңизди тескей турган VPN\'ге да туташып турасыз."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактык аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди көзөмөлдөй турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Электрондук почта, колдонмолор жана вебсайттар сыяктуу тармактагы жеке аракеттериңизди тескей турган <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосуна туташып турасыз."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION">%2$s</xliff:g> менен туташкан.\n\nКөбүрөөк маалымат алуу үчүн администраторуңузга кайрылыңыз."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> менен туташкан.\n\nМындан тышкары, тармактагы жеке аракеттериңизди көзөмөлдөгөн <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Түзмөктүн кулпусу кол менен ачылмайынча кулпуланган бойдон алат"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Эскертмелерди тезирээк алуу"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жайып көрсөтүү"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жыйнап коюу"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран кадалган"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Карап чыгуу\" баскычтарын басып, кармап туруңуз."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Карап чыгуу\" баскычын басып, кармап туруңуз."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Түшүндүм"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Жок, рахмат"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Күйүк"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өчүк"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Бул функциянын жардамы менен ар бир колдонмо үчүн эскертменин маанилүүлүк деңгээлин 0дон 5ке чейин койсоңуз болот. \n\n"<b>"5-деңгээл"</b>" \n- Эскертмелер тизмесинин башында көрсөтүлсүн \n- Эскертмелер толук экранда көрсөтүлсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"4-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"3-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n\n"<b>"2-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n\n"<b>"1-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n- Кулпуланган экрандан жана абал тилкесинен жашырылсын \n- Эскертмелер тизмесинин аягында көрсөтүлсүн \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык эскертмелер бөгөттөлсүн"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Эскертмелер"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Мындан ары бул эскертмелер сизге жөнөтүлбөйт."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> колдонмосунун төмөнкү каналга жөнөткөн эскертмелери"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Төмөн"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Орточо"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Жогору"</string>
+    <string name="high_importance" msgid="730741630855788381">"Шашылыш"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Добуш да чыгарбасын, экранда да көрсөтүлбөсүн"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Добуш чыгарсын"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Добуш менен экранга калкып чыксын"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
     <string name="notification_done" msgid="5279426047273930175">"Бүттү"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> эскертмесин башкаруу каражаттары"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7eefe2e..7fb5c1e 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ລັອກ​ໜ້າ​ຈໍ."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ການ​ຕັ້ງ​ຄ່າ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"​ພາບ​ຮວມ."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ໜ້າຈໍລັອກວຽກ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ປິດ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ປິດ Wi-Fi ແລ້ວ."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳ​ເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ໂໝດການເຮັດວຽກ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ແສງກາງຄືນ"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ທ່ານລຶບລ້າງທຸກຢ່າງແລ້ວ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການ​ແຍກ​ລວງ​ຂວາງ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການ​ແຍກ​ລວງ​ຕັ້ງ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການ​ແຍກ​ກຳ​ນົດ​ເອງ"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"ຕັດ​ການ​ເຊື່ອມ​ຕໍ່ VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ອຸປະກອນຂອງທ່ານແມ່ນຈັດການໂດຍ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ໃຊ້ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ເພື່ອຈັດການອຸປະກອນຂອງທ່ານ."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານສາມາດຕິດຕາມ ແລະ ຈັດການການຕັ້ງຄ່າ, ການເຂົ້າເຖິງອົງກອນ, ແອັບ, ຂໍ້ມູນທີ່ເຊື່ອມໂຍງກັບອຸປະກອນຂອງທ່ານແລະ ຂໍ້ມູນສະຖານທີ່ຂອງອຸປະກອນທ່ານໄດ້."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ສຶກສາເພີ່ມເຕີມ"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="VPN_APP">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍ, ຮວມທັງອີເມວ, ແອັບ ແລະ ເວັບໄຊຕ່າງໆໄດ້."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"ເປີດການຕັ້ງຄ່າ VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານໄດ້ເປີດໃຊ້ການບັນທຶກເຄືອຂ່າຍໄວ້, ເຊິ່ງຈະກວດສອບທຣາບຟິກໃນອຸປະກອນຂອງທ່ານ.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"ທ່ານໄດ້ອະນຸຍາດໃຫ້ແອັບຕັ້ງການເຊື່ອມຕໍ່ VPN.\n\nແອັບນີ້ສາມາດຕິດຕາມການເຄື່ອນໄຫວຂອງອຸປະກອນ ແລະເຄືອຂ່າຍຂອງທ່ານ ເຊິ່ງລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"ໂປ​ຣ​ໄຟ​ລ໌​ວຽກ​ຂອງ​ທ່ານ​ຖືກ​ຄຸ້ມ​ຄອງ​ໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ​ສາ​ມາດ​ຕິດ​ຕາມການ​ເຄື່ອນ​ໄຫວ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ​ໄດ້​ ລວມ​ທັງ​ອີ​ເມວ, ແອັບ, ແລະ​ເວັບ​ໄຊ​ທ໌​.\n\nສຳ​ລັບ​ຂໍ້​ມູນ​ເພີ່ມ​ເຕີມ, ຕິດ​ຕໍ່​ຜູ້​ຄວບ​ຄຸມ​ຂອງ​ທ່ານ.\n\nທ່ານ​ຍັງ​ເຊື່ອມ​ຕໍ່​ກັບ VPN, ເຊິ່ງ​ສາ​ມາດ​ຕິດ​ຕາມ​ກິດ​ຈະ​ກຳ​ເຄືອ​ຂ່າຍ​​ຂອງ​ທ່ານ."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ລວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊທ໌."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%1$s</xliff:g> ແລ້ວ, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ ຮວມທັງອີເມວ, ​ແອັບ ແລະເວັບໄຊໄດ້."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຄວບຄຸມໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນຖືກເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ,​ ແອັບ ແລະເວັບໄຊທ໌.\n\nສຳລັບຂໍ້ມູນເພີ່ມເຕີມ, ໃຫ້ຕິດຕໍ່ຜູ້ບໍລິຫານຂອງທ່ານ."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍບ່ອນເຮັດວຽກຂອງທ່ານ ລວມທັງອີເມວ, ແອັບ ແລະເວັບໄຊທ໌.\n\nທ່ານເຊື່ອມຕໍ່ກັບ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານ."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Device will stay locked until you manually unlock"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ຮັບເອົາການ​ແຈ້ງເຕືອນ​ໄວຂຶ້ນ"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ຂະຫຍາຍ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ຫຍໍ້ລົງ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ປັກ​ໝຸດໜ້າ​ຈໍ​ແລ້ວ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ເຂົ້າໃຈແລ້ວ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ບໍ່, ຂອບໃຈ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼື​ບໍ່?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ເປີດ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ປິດ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ດ້ວຍການຄວບຄຸມການແຈ້ງເຕືອນ, ທ່ານສາມາດຕັ້ງລະດັບຄວາມສຳຄັນຈາກ 0 ຮອດ 5 ໃຫ້ກັບການແຈ້ງເຕືອນແອັບໃດໜຶ່ງໄດ້. \n\n"<b>"ລະດັບ 5"</b>" \n- ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ \n- ອະນຸຍາດໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 4"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 3"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n\n"<b>"ລະດັບ 2"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n\n"<b>"ລະດັບ 1"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n- ເຊື່ອງຈາກໜ້າຈໍລັອກ ແລະ ແຖບສະຖານະ \n- ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນ \n\n"<b>"ລະດັບ 0"</b>" \n- ປິດກັ້ນການແຈ້ງເຕືອນທັງໝົດຈາກແອັບ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ການແຈ້ງເຕືອນ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ການແຈ້ງເຕືອນ <xliff:g id="APP">%s</xliff:g> ສຳລັບ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ຕໍ່າ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ປານກາງ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ສູງ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ດ່ວນ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ບໍ່ມີສຽງ ຫຼື ການລົບກວນໃນໜ້າຈໍ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ສະແດງແບບງຽບໆ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ເຮັດສຽງ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ເຮັດສຽງດັງ ແລະ ສະແດງຂຶ້ນໃນໜ້າຈໍ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"ການຄວບຄຸມການແຈ້ງເຕືອນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 649e42a..6036842 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Užrakinimo ekranas."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nustatymai"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Apžvalga."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Darbo profilio užrakinimo ekranas"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Uždaryti"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"„Wi-Fi“ ryšys išjungtas."</string>
@@ -326,6 +325,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darbo režimas"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nakties šviesa"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nėra jokių naujausių elementų"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Viską išvalėte"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
@@ -339,6 +344,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikalus skaidymas"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tinkintas skaidymas"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
@@ -419,20 +434,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Atjungti VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Įrenginį tvarko „<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>“."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"„<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>“ naudoja „<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>“ įrenginiui tvarkyti."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administr. gali stebėti ir tvark. nustat., įmonės prieigos par., progr., su įreng. susietus duomenis ir įreng. vietovės inform."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Sužinoti daugiau"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Esate prisijungę prie programos „<xliff:g id="VPN_APP">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Atidaryti VPN nustatymus"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administratorius įjungė tinklo duomenų įrašymą į žurnalą. Įjungus šią funkciją stebimas srautas jūsų įrenginyje.\n\nJei reikia daugiau informacijos, susisiekite su administratoriumi."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Suteikėte programai leidimą nustatyti VPN ryšį.\n\nŠi programa gali stebėti įrenginio ir tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Jūsų darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“.\n\nAdministratorius gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi.\n\nBe to, esate prisijungę prie VPN, kuris gali stebėti tinklo veiklą."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Esate prisijungę prie programos „<xliff:g id="APPLICATION">%1$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nDaugiau informacijos galite gauti susisiekę su administratoriumi."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Jis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti darbo profilio tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio profilio tinklo veiklą."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Įrenginys liks užrakintas, kol neatrakinsite jo neautomatiniu būdu"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Greičiau gaukite pranešimus"</string>
@@ -444,10 +463,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Išskleisti"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sutraukti"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekranas prisegtas"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Apžvalga“, kad atsegtumėte."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Supratau"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, ačiū"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
@@ -514,28 +531,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Įjungta"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Išjungta"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Naudodami pranešimų valdiklius galite nustatyti programos pranešimų svarbos lygį nuo 0 iki 5. \n\n"<b>"5 lygis"</b>" \n– Rodyti pranešimų sąrašo viršuje \n– Leisti pertraukti, kai veikia viso ekrano režimas \n– Visada rodyti pranešimus \n\n"<b>"4 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Visada rodyti pranešimus \n\n"<b>"3 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n\n"<b>"2 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n– Niekada neleisti garso ir nevibruoti \n\n"<b>"1 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n– Niekada neleisti garso ir nevibruoti \n– Slėpti užrakinimo ekrane ir būsenos juostoje \n– Rodyti pranešimų sąrašo apačioje \n\n"<b>"0 lygis"</b>" \n– Blokuoti visus programos pranešimus"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Pranešimai"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nebegausite šių pranešimų."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"„<xliff:g id="APP">%s</xliff:g>“ pranešimai, skirti"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nelabai svarbus"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Vidutiniškai svarbus"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Svarbus"</string>
+    <string name="high_importance" msgid="730741630855788381">"Skubus"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Neskambėti ir nepertraukti vaizdo"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Rodyti tyliai"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Skambėti"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Skambėti ir iššokti ekrane"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
     <string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų valdikliai"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c230313..9911109 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Bloķēšanas ekrāns."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Iestatījumi"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pārskats."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Darba profila bloķēšanas ekrāns"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Aizvērt"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi ir izslēgts."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darba režīms"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nakts režīms"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nav nesenu vienumu"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Visi uzdevumi ir notīrīti"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikāls dalījums"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pielāgots dalījums"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Atvienot VPN tīklu"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Jūsu ierīci pārvalda <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> izmanto lietotni <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> jūsu ierīces pārvaldībai."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administrators var pārraudzīt un pārvaldīt iestatījumus, korporatīvo piekļuvi, lietotnes, ierīces datus un informāciju par ierīces atrašanās vietu."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Uzzināt vairāk"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Ir izveidots savienojums ar lietotni <xliff:g id="VPN_APP">%1$s</xliff:g>, kas var pārraudzīt jūsu darbības tīklā, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Atvērt VPN iestatījumus"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administrators ir ieslēdzis tīkla reģistrēšanu, kuru izmanto, lai pārraudzītu datplūsmu jūsu ierīcē.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Jūs piešķīrāt lietotnei atļauju izveidot savienojumu ar VPN tīklu.\n\nŠī lietotne var pārraudzīt jūsu ierīcē un tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJūsu administrators var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru.\n\nIerīcē ir arī izveidots savienojums ar VPN tīklu, kurā var tikt pārraudzītas jūsu tīklā veiktās darbības."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ir izveidots savienojums ar lietotni <xliff:g id="APPLICATION">%1$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nLai iegūtu plašāku informāciju, sazinieties ar administratoru."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Tas ir saistīts ar lietojumprogrammu <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp e-pasta ziņojumus, lietotnes un vietnes.\n\nIr piesaistīta arī lietojumprogramma <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Ierīce būs bloķēta, līdz to manuāli atbloķēsiet."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Saņemiet paziņojumus ātrāk"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Izvērst"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sakļaut"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrāns ir piesprausts"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām Atpakaļ un Pārskats un turiet tās."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogai Pārskats un turiet to."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Sapratu!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nē, paldies"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vai paslēpt vienumu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ieslēgts"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izslēgts"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Izmantojot barošanas paziņojumu vadīklas, varat lietotnes paziņojumiem iestatīt svarīguma līmeni (no 0 līdz 5). \n\n"<b>"5. līmenis"</b>" \n- Tiek rādīts paziņojumu saraksta augšdaļā \n- Tiek atļauta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"4. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"3. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n\n"<b>"2. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n\n"<b>"1. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n- Paziņojumi tiek paslēpti bloķēšanas ekrānā un statusa joslā \n- Paziņojumi tiek rādīti paziņojumu saraksta apakšdaļā \n\n"<b>"0. līmenis"</b>" \n- Visi lietotnes paziņojumi tiek bloķēti"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Paziņojumi"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Jūs vairs nesaņemsiet šos paziņojumus."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Lietotnes <xliff:g id="APP">%s</xliff:g> paziņojumi par"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Mazsvarīgs"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Vidēji svarīgs"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Ļoti svarīgs"</string>
+    <string name="high_importance" msgid="730741630855788381">"Steidzams"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez skaņas signāla vai vizuāla paziņojuma"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Rādīt bez skaņas signāla"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Atskaņot skaņas signālu"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Atskaņot skaņas signālu un īslaicīgi parādīt ekrānā"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumu vadīklas"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 110812b..500cb4f 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заклучи екран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Поставки"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Краток преглед."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Работен заклучен екран"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Затвори"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi е исклученo."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупредување за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим на работа"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ноќно светло"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Нема неодамнешни ставки"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Исчистивте сѐ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информации за апликацијата"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Раздели вертикално"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Раздели прилагодено"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Наполнета"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Исклучи ВПН"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> управува со уредов."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ја користи <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> за да управува со вашиот уред."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Админ. може да следи и да управува со: поставки, корпоративен пристап, апликации, податоци за уредот и информации за локација."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Дознајте повеќе"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Поврзани сте на <xliff:g id="VPN_APP">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-сајтовите."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Отворете „Поставки за VPN“"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Вашиот администратор вклучил евиденција на мрежата, што подразбира следење на сообраќајот на вашиот уред.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Дозволивте апликацијата да постави поврзување преку ВПН.\n\nАпликацијата може да го следи уредот и активноста на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил.\n\nАдминистратор е во можност да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот.\n\nИсто така, поврзани сте на ВПН, којашто може да ја следи вашата активност на мрежата."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"ВПН"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Поврзани сте на <xliff:g id="APPLICATION">%1$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nЗа повеќе информации, контактирајте со администраторот."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> управува со вашиот работен профил. Истиот е поврзан на <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, којашто може да ја следи вашата работна активност на мрежата, вклучувајќи ги е-пораките, апликациите и веб-локациите.\n\nВие исто така сте поврзани на <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, којашто може да ја следи вашата лична активност на мрежата."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Уредот ќе остане заклучен додека рачно не го отклучите"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Добивајте известувања побрзо"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Собери"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранот е прикачен"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Сфатив"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, фала"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Вклучено"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Исклучено"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Со контролите за известувањата за напојување, може да поставите ниво на важност од 0 до 5 за известувањата на која било апликација. \n\n"<b>"Ниво 5"</b>" \n- Прикажувај на врвот на списокот со известувања \n- Дозволи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 4"</b>" \n- Спречи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 3"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n\n"<b>"Ниво 2"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n\n"<b>"Ниво 1"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n- Сокриј од заклучен екран и статусна лента \n- Прикажувај на дното на списокот со известувања \n\n"<b>"Ниво 0"</b>" \n- Блокирај ги сите известувања од апликацијата"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Известувања"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Веќе нема да ги добивате овие известувања."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Известувања од <xliff:g id="APP">%s</xliff:g> за"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ниско"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средно"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Високо"</string>
+    <string name="high_importance" msgid="730741630855788381">"Итно"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звук или визуелен прекин"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Прикажи тивко"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Испушти звук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Испушти звук и прикажи го на екранот"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известувања на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 4c4a99b..1787d21 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ലോക്ക് സ്‌ക്രീൻ."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ക്രമീകരണം"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"കാഴ്ച."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ഔദ്യോഗിക ലോക്ക് സ്ക്രീൻ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"അടയ്‌ക്കുക"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"വൈഫൈ ഓഫാക്കി."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"പ്രവർത്തന മോഡ്"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"നൈറ്റ് ലൈറ്റ്"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"നിങ്ങൾ എല്ലാം മായ്ച്ചിരിക്കുന്നു"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ആപ്പ് വിവരം"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്‌ടാനുസൃതമായി വേർതിരിക്കുക"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ചാർജായി"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN വിച്‌ഛേദിക്കുക"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"നിങ്ങളുടെ ഉപകരണം മാനേജുചെയ്യുന്നത് <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ആണ്."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"നിങ്ങളുടെ ഉപകരണം മാനേജുചെയ്യാൻ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ഉപയോഗിക്കുന്നത് <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ആണ്."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"ഈ ഉപകരണവുമായി ബന്ധപ്പെട്ട ക്രമീകരണം, കോർപ്പറേറ്റ് ആക്‌സസ്സ്, ആപ്‌സ്, വിവരങ്ങൾ എന്നിവയും  ഉപകരണത്തിന്റെ ലൊക്കേഷൻ വിവരവും നിരീക്ഷിക്കാനും മാനേജുചെയ്യാനും അഡ്‌മിനിസ്‌ട്രേറ്റർക്ക് കഴിയും."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" 5"</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"കൂടുതലറിയുക"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"നിങ്ങൾ <xliff:g id="VPN_APP">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" 5"</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN ക്രമീകരണം തുറക്കുക"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"നിങ്ങളുടെ അഡ്മിൻ, ഉപകരണത്തിലെ ട്രാഫിക്ക് നിരീക്ഷിക്കുന്ന നെറ്റ്‌വർക്ക് ലോഗിംഗ് ഓണാക്കിയിട്ടുണ്ട്.\n\nകൂടുതൽ വിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN കണക്ഷൻ സജ്ജീകരിക്കാൻ നിങ്ങൾ ഒരു ആപ്പിന് അനുമതി നൽകി.\n\nഈ ആപ്പിന് നിങ്ങളുടെ ഇമെയിലുകളും ആപ്സും വെബ്‌സൈറ്റുകളും ഉൾപ്പെടെ, ഉപകരണവും നെറ്റ്‌വർക്ക് പ്രവർത്തനവും നിരീക്ഷിക്കാൻ കഴിയും."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്.\n\nനിങ്ങളുടെ അഡ്‌മിനിസ്ട്രേറ്റർക്ക് ഇമെയിലുകളും അപ്ലിക്കേഷനുകളും സുരക്ഷിത വെബ്‌സൈറ്റുകളും ഉൾപ്പെടെയുള്ള നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാൻ കഴിയും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, അഡ്‌മിനിസ്ട്രേറ്ററെ ബന്ധപ്പെടുക.\n\nനിങ്ങളുടെ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകുന്ന ഒരു VPN-ലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്തിരിക്കുന്നു."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക്, നിങ്ങളുടെ അഡ്‌മിനിസ്‌ട്രേറ്ററെ ബന്ധപ്പെടുക."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ നിയന്ത്രിക്കുന്നത് <xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ്. നിങ്ങൾ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും.\n\nനിങ്ങൾ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> എന്നതിലേക്കും കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ സ്വകാര്യ നെറ്റ്‌വർക്ക് പ്രവർത്തനം നിരീക്ഷിക്കാനാകും."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"നിങ്ങൾ സ്വമേധയാ അൺലോക്കുചെയ്യുന്നതുവരെ ഉപകരണം ലോക്കുചെയ്‌തതായി തുടരും"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"അറിയിപ്പുകൾ വേഗത്തിൽ സ്വീകരിക്കുക"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"വികസിപ്പിക്കുക"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ചുരുക്കുക"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"സ്‌ക്രീൻ പിൻ ചെയ്‌തു"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്‌പർശിച്ച് പിടിക്കുക."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'ചുരുക്കവിവരണം\' സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"മനസ്സിലായി"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"വേണ്ട, നന്ദി"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> എന്നത് മറയ്‌ക്കണോ?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ഓൺ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ഓഫ്"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"പവർ അറിയിപ്പ് നിയന്ത്രണം ഉപയോഗിച്ച്, ഒരു ആപ്പിനായുള്ള അറിയിപ്പുകൾക്ക് 0 മുതൽ 5 വരെയുള്ള പ്രാധാന്യ ലെവലുകളിലൊന്ന് നിങ്ങൾക്ക് സജ്ജമാക്കാവുന്നതാണ്. \n\n"<b>"ലെവൽ 5"</b>" \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ മുകളിൽ കാണിക്കുക \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം അനുവദിക്കുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 4"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 3"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും സൃശ്യമാക്കരുത് \n\n"<b>"ലെവൽ 2"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n\n"<b>"ലെവൽ 1"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n- ലോക്ക് സ്ക്രീനിൽ നിന്നും സ്റ്റാറ്റസ് ബാറിൽ നിന്നും മറയ്ക്കുക \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ അടിയിൽ കാണിക്കുക \n\n"<b>"ലെവൽ 0"</b>" \n- ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്കുചെയ്യുക"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"അറിയിപ്പുകൾ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"നിങ്ങൾക്ക് ഈ അറിയിപ്പുകൾ ഇനിയങ്ങോട്ട് ലഭിക്കില്ല."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ഇനിപ്പറയുന്നതിനുള്ള <xliff:g id="APP">%s</xliff:g> അറിയിപ്പുകൾ:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"കുറഞ്ഞ പ്രാധാന്യം"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ഇടത്തരം പ്രാധാന്യം"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ഉയർന്ന പ്രാധാന്യം"</string>
+    <string name="high_importance" msgid="730741630855788381">"അടിയന്തിര പ്രാധാന്യം"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ശബ്ദപരമോ ദൃശ്യപരമോ ആയ തടസ്സമില്ല"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"നിശബ്ദമായി കാണിക്കുക"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ശബ്ദമുണ്ടാക്കുക"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ശബ്ദമുണ്ടാക്കുക, സ്ക്രീനിൽ കാണിക്കുക"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
     <string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0433950..b8b9222 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -183,8 +183,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Дэлгэц түгжих."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Тохиргоо"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Тойм"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ажлын түгжигдсэн дэлгэц"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Хаах"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi унтраасан."</string>
@@ -320,6 +319,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> анхааруулга"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ажлын горим"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Шөнийн гэрэл"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Сүүлийн үеийн зүйл байхгүй"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Та бүгдийг нь устгасан"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
@@ -333,6 +338,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Босоо чиглэлд хуваах"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Хүссэн хэлбэрээр хуваах"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Цэнэглэгдсэн"</string>
@@ -413,20 +428,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN таслах"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Таны төхөөрөмжийг <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> удирддаг."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> таны төхөөрөмжийг удирдахын тулд <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>-г ашигладаг."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Таны админ тохиргоо, байгууллагын хандалт, апп, төхөөрөмжтэй холбоотой өгөгдөл болон төхөөрөмжийн байршлын мэдээллийг хянах, удирдах боломжтой."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Дэлгэрэнгүй үзэх"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="VPN_APP">%1$s</xliff:g>-д холбогдсон байна."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN тохиргоог нээх"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна.\n\nДэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вэбсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\nАдмин нь таны имэйл,апп болон вэбсайт зэрэг сүлжээний үйл ажиллагааг хянадаг. \n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу. \n\nМөн та VPN-д холбогдсон бөгөөд ингэснээр өөрийн сүлжээний үйл ажиллагааг хянах боломжтой байна."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны  имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вэбсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Таныг гараар онгойлгох хүртэл төхөөрөмж түгжээтэй байх болно"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Мэдэгдлийг хурдан авах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index fef7d65..4c8d59c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"लॉक स्क्रीन."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिंग्ज"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"विहंगावलोकन."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"कार्य लॉक स्क्रीन"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"बंद करा"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi बंद झाले."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रीचा प्रकाश"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"अलीकडील कोणतेही आयटम नाहीत"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपण सर्वकाही साफ केले"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग माहिती"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज झाली"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN डिस्कनेक्ट करा"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"आपले डिव्हाइस <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ने व्यवस्थापित केले आहे."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"आपले डिव्हाइस व्यवस्थापित करण्यासाठी <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> वापरते."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"आपला प्रशासक सेटिंग्ज, कॉर्पोरेट प्रवेश, अॅप्स, आपल्या डिव्हाइसशी संबद्ध डेटा आणि आपल्या डिव्हाइसच्या स्थान माहितीचे परीक्षण करू आणि ते व्यवस्थापित करू शकतो."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"अधिक जाणून घ्या"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"आपण <xliff:g id="VPN_APP">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN सेटिंग्ज उघडा"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"आपल्या प्रशासकाने नेटवर्क लॉगिंग चालू केले आहे, जे आपल्या डिव्हाइस वरील रहदारीचे परीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"आपण VPN कनेक्शन सेट करण्यासाठी अ‍ॅपला परवानगी दिली.\n\nहा अ‍ॅप ईमेल, अ‍ॅप्स आणि वेबसाइटसह, आपल्या डिव्हाइस आणि नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे.\n\nआपला प्रशासक ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा.\n\nआपण एका VPN शी देखील कनेक्ट केले आहे, जो आपल्या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो.\n\nअधिक माहितीसाठी, आपल्‍या प्रशासकाशी संपर्क साधा."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपले कार्य प्रोफाईल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले आहे. ते <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nआपण <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शी देखील कनेक्‍ट केले आहे, जे आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"आपण व्यक्तिचलितपणे अनलॉक करेपर्यंत डिव्हाइस लॉक केलेले राहील"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"सूचना अधिक जलद मिळवा"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करा"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संकुचित करा"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"स्क्रीन पिन केलेली आहे"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"आपण अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"आपण अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"समजले"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"नाही धन्यवाद"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"चालू"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"बंद"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"उर्जा सूचना नियंत्रणांसह, आपण अॅपच्या सूचनांसाठी महत्त्व स्तर 0 ते 5 पर्यंत सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दर्शवा \n- पूर्ण स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n\n"<b>"स्तर 1"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना अवरोधित करा"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"आपल्याला यापुढे या सूचना प्राप्त होणार नाहीत."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"यासाठी <xliff:g id="APP">%s</xliff:g> सूचना"</string>
+    <string name="min_importance" msgid="7559703098688382595">"निम्न"</string>
+    <string name="low_importance" msgid="6891335321576225228">"मध्‍यम"</string>
+    <string name="default_importance" msgid="6400766013567512061">"सर्वाधिक"</string>
+    <string name="high_importance" msgid="730741630855788381">"त्वरित"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"कोणताही ध्वनी किंवा व्हिज्युअल व्यत्यय नाही"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"शांतपणे दर्शवा"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ध्वनी करा"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ध्वनी करा आणि स्क्रीनवर पॉप करा"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
     <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> सूचना नियंत्रणे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index d6c90a9..6e29cc9 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Kunci skrin."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Tetapan"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ikhtisar."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Skrin kunci kerja"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Tutup"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi dimatikan."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mod kerja"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Cahaya Malam"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Tiada item terbaharu"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda telah mengetepikan semua item"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Menegak Terpisah"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tersuai Terpisah"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Putuskan sambungan VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Peranti anda diurus oleh <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> menggunakan <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> untuk mengurus peranti anda."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Pentadbir anda boleh memantau dan mengurus tetapan, akses korporat, apl, data yang dikaitkan dengan peranti dan maklumat lokasi peranti anda."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ketahui lebih lanjut"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Anda disambungkan ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Buka Tetapan VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Pentadbir anda telah menghidupkan pengelogan rangkaian yang memantau trafik pada peranti anda.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Anda memberikan kebenaran kepada apl untuk menyediakan sambungan VPN.\n\nApl ini boleh memantau aktiviti peranti dan rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nPentadbir anda boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda.\n\nAnda turut disambungkan ke VPN, yang boleh memantau aktiviti rangkaian anda."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian anda, termasuk e-mel, apl dan tapak web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil ini disambungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, sila hubungi pentadbir anda."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil disambungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut disambungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Peranti akan kekal terkunci sehingga anda membuka kunci secara manual"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Dapatkan pemberitahuan lebih cepat"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kembangkan"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Runtuhkan"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrin telah disemat"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Ikhtisar untuk menyahsemat."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Ikhtisar untuk menyahsemat."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Faham"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Tidak"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Hidup"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Mati"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Dengan kawalan pemberitahuan berkuasa, anda boleh menetapkan tahap kepentingan dari 0 hingga 5 untuk pemberitahuan apl. \n\n"<b>"Tahap 5"</b>" \n- Tunjukkan pada bahagian atas senarai pemberitahuan \n- Benarkan gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 4"</b>" \n- Halang gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 3"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n\n"<b>"Tahap 2"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi dan bergetar \n\n"<b>"Tahap 1"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi atau bergetar \n- Sembunyikan daripada skrin kunci dan bar status \n- Tunjukkan di bahagian bawah senarai pemberitahuan \n\n"<b>"Tahap 0"</b>" \n- Sekat semua pemberitahuan daripada apl"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Pemberitahuan"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Anda tidak akan menerima pemberitahuan ini lagi."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Pemberitahuan <xliff:g id="APP">%s</xliff:g> untuk"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Rendah"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Sederhana"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Tinggi"</string>
+    <string name="high_importance" msgid="730741630855788381">"Segera"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Tiada gangguan bunyi atau visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Tunjukkan secara senyap"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Berbunyi"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Berbunyi dan paparkan pada skrin"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
     <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kawalan pemberitahuan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 17eeacf..a439a01 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"မျက်နှာပြင် သော့ပိတ်ရန်"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ဆက်တင်များ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ခြုံကြည့်မှု။"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"အလုပ်သုံး လော့ခ်မျက်နှာပြင်"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ပိတ်ရန်"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>။"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ကြိုးမဲ့ ပိတ်ထား။"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> သတိပေးချက်"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"အလုပ် မုဒ်"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ညအလင်းရောင်"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"သင်အားလုံးကို ရှင်းလင်းပြီးပါပြီ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"အပလီကေးရှင်းအင်ဖို"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"အားသွင်းပြီး"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ကို အဆက်ဖြတ်ရန်"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"သင့်စက်ပစ္စည်းကို <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> က စီမံခန့်ခွဲထားပါသည်။"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> သည် သင့်စက်ပစ္စည်းကို စီမံခန့်ခွဲရန် <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ကို အသုံးပြုပါသည်။"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"စီမံသူသည် ဆက်တင်၊ ကော်ပိုရိတ် သုံးခွင့်၊ အက်ပ်၊ စက်ပစ္စည်းနှင့် ဆက်စပ်ဒေတာနှင့် ၎င်း၏တည်နေရာအချက်အလက်ကိုစောင့်ကြည့်စီမံနိုင်ပါသည်။"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ပိုမိုလေ့လာရန်"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="VPN_APP">%1$s</xliff:g> သို့ သင်သည် ချိတ်ဆက်ထားပါသည်။"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Open VPN ဆက်တင်များ"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"သင့်စီမံခန့်ခွဲသူသည် သင့်စက်ပစ္စည်းပေါ်ရှိ ဒေတာအသွားအလာကို စောင့်ကြည့်နိုင်သည့် ကွန်ရက်မှတ်တမ်းတင်ခြင်းကို ဖွင့်ထားပါသည်။\n\nထပ်မံလေ့လာရန်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN ချိတ်ဆက်မှုပြုလုပ်ရန် အက်ပ်ကို သင်ခွင့်ပြုလိုက်သည်။ \n\n ဤအက်ပ်သည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g>မှ စီမံခန့်ခွဲပါသည်။ \n\nသင့်စီမံခန့်ခွဲသူသည် အီးမေးလ်များ၊ အက်ပ်များ၊ နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောက်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။ \n\nသင်သည် VPN တစ်ခုသို့ပါ ချိတ်ဆက်ထားပြီး ၎င်းကပါ သင်၏ ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်ပါသည်။"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးများ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"သင်သည် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"သင်သည် အီးမေးလ်၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်ကိုယ်ရေးကိုယ်တာ ကွန်ရက်အသုံးပြုမှုကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"သင့်အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\nအချက်အလက်များ ပိုမိုရယူရန် သင်၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"သင့်အလုပ် ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> မှစီမံခန့်ခွဲသည်။ ၎င်းကို <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်၊ ၎င်းသည် အီးမေးလ်များ၊ အက်ပ်များနှင့် ဝဘ်ဆိုက်များအပါအဝင် သင့်အလုပ်ကွန်ရက်လုပ်ဆောင်ချက်ကို စောင့်ကြည့်နိုင်သည်။ \n\n သင်သည်<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ကိုလည်း ချိတ်ဆက်ထားသည်၊ ၎င်းသည် သင့်ကိုယ်ပိုင်ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည်။"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"သင်က လက်ဖြင့် သော့မဖွင့်မချင်း ကိရိယာမှာ သော့ပိတ်လျက် ရှိနေမည်"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"အကြောင်းကြားချက်များ မြန်မြန်ရရန်"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"တိုးချဲ့ရန်"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ခေါက်သိမ်းရန်..."</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"မျက်နှာပြင် ပင်ထိုးပြီးပါပြီ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"သင်ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် Overview ကိုထိပြီး ဖိထားပါ။"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"အဲဒါ ရပါပြီ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"မလိုတော့ပါ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ဝှက်မည်လား?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ဖွင့်ပါ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ပိတ်ပါ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ပါဝါအကြောင်းကြားချက် ထိန်းချုပ်မှုများကိုအသုံးပြုပြီး အက်ပ်တစ်ခု၏ အကြောင်းကြားချက် အရေးပါမှု ၀ မှ ၅ အထိသတ်မှတ်ပေးနိုင်သည်။ \n\n"<b>"အဆင့် ၅"</b>" \n- အကြောင်းကြားချက်စာရင်း၏ ထိပ်ဆုံးတွင် ပြသည် \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်းကို ခွင့်ပြုသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၄"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၃"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n\n"<b>"အဆင့် ၂"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n\n"<b>"အဆင့် ၁"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n- လော့ခ်ချထားသည့် မျက်နှာပြင်နှင့် အခြေအနေဘားတန်းတို့တွင် မပြပါ \n- အကြောင်းကြားချက်စာရင်း အောက်ဆုံးတွင်ပြသည် \n\n"<b>"အဆင့် ၀"</b>" \n- အက်ပ်မှ အကြောင်းကြားချက်များ အားလုံးကို ပိတ်ဆို့သည်"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"အကြောင်းကြားချက်များ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"သင်သည် ဤအကြောင်းကြားချက်များကို လက်ခံရရှိတော့မည် မဟုတ်ပါ။"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ဤအရာအတွက် <xliff:g id="APP">%s</xliff:g> အကြောင်းကြားချက်များ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"အရေးသိပ်မကြီးပါ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"အတော်အသင့်"</string>
+    <string name="default_importance" msgid="6400766013567512061">"အရေးကြီးသည်"</string>
+    <string name="high_importance" msgid="730741630855788381">"အရေးပေါ်"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"မည်သည့်အသံ သို့မဟုတ် ရုပ်ပုံ ကြားဝင်နှောင့်ယှက်ခြင်း မရှိပါ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"တိတ်တဆိတ်ပြပါ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"အသံဖွင့်ပါ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"အသံဖွင့်၍ မျက်နှာပြင်ပေါ်တွင် ပြပါ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b5f915d..d95dd29 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskjerm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Innstillinger"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Oversikt."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Låseskjerm for arbeid"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Lukk"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi er slått av."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeidsmodus"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattlys"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Ingen nylige elementer"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har fjernet alt"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Koble fra VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Enheten din administreres av <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> bruker <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> til å administrere enheten din."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administratoren din kan overvåke og administrere innstillinger, bedriftstilgang, apper, data som er tilknyttet denne enheten, og enhetens posisjonsinformasjon."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Finn ut mer"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Enheten er koblet til <xliff:g id="VPN_APP">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Åpne VPN-innstillingene"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administratoren din har slått på loggføring av nettverk, som overvåker trafikken på enheten din.\n\nKontakt administratoren for mer informasjon."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Du ga en app tillatelse til å konfigurere en VPN-tilkobling.\n\nDenne appen kan overvåke enheten og nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratoren din kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder.\n\nFor mer informasjon, ta kontakt med administratoren.\n\nDu er også koblet til et VPN, som kan overvåke nettverksaktiviteten din."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nFor å få mer informasjon, ta kontakt med administratoren."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Work-profilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-post, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten forblir låst til du låser den opp manuelt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Motta varsler raskere"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Oversikt for å løsne den."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"På"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Av"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med effektive varselinnstillinger kan du angi viktighetsnivåer fra 0 til 5 for appvarsler. \n\n"<b>"Nivå 5"</b>" \n– Vis øverst på varsellisten \n– Tillat forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 4"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 3"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n\n"<b>"Nivå 2"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri fort \n– Tillat aldri lyder eller vibrering \n\n"<b>"Nivå 1"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n– Tillat aldri lyder eller vibrering \n– Skjul fra låseskjermen og statusfeltet \n– Vis nederst på varsellisten \n\n"<b>"Nivå 0"</b>" \n– Blokkér alle varsler fra appen"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Varsler"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Du får ikke disse varslene lenger."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-varsler for"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Lav"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Middels"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Høy"</string>
+    <string name="high_importance" msgid="730741630855788381">"Haster"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ingen lyd eller visuell forstyrrelse"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Vis uten lyd"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Lag lyd"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Lag lyd og vis i forgrunnen"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Varselinnstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 0d20b04..296d934 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"स्क्रीन बन्द गर्नुहोस्।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिङहरू"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"सारांश।"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"कार्य प्रोफाइलको लक स्क्रिन"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"बन्द गर्नुहोस्"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi बन्द गरियो।"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रिको प्रकाश"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"हालका कुनै पनि वस्तुहरू छैनन्"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"तपाईँले सबै कुरा खाली गर्नुभएको छ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग जानकारी"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"आफू अनुकूल विभाजन गर्नुहोस्"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"चार्ज भयो"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"विच्छेद VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"तपाईंको यन्त्र <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> द्वारा व्यवस्थापन गरिएको छ।"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ले तपाईंको यन्त्रको व्यवस्थापन गर्न <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> को प्रयोग गर्दछ।"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"तपाईंको प्रशासकले सेटिङ, संस्थागत पहुँच, अनुप्रयोग, तपाईंको यन्त्रसँग सम्बन्धित डेटा र तपाईंको यन्त्रको स्थान सम्बन्धी जानकारीको अनुगमन तथा व्यवस्थापन गर्न सक्नुहुन्छ।"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"थप जान्नुहोस्"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"तपाईं <xliff:g id="VPN_APP">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायत तपाईंको नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN सम्बन्धी सेटिङहरू खोल्नुहोस्"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"तपाईंको प्रशासकले तपाईंको यन्त्रमा ट्राफिकको अनुगमन गर्ने नेटवर्कको लगिङलाई सक्रिय गर्नुभएको छ।\n\nथप जानकरीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"तपाईँले VPN जडान गर्न अनुप्रयोगलाई अनुमति दिनुभयो।\n\nयो अनुप्रयोगले तपाईँका यन्त्र र  नेटवर्क गतिविधि लगायत इमेल, अनुप्रयोग र वेबसाइटहरू अनुगमन गर्न सक्छ।"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g>द्वारा व्यवस्थापन गरिन्छ।.\n\nतपाईँको प्रशासक इमेल, अनुप्रयोगहरू, र सुरक्षित वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्षम छ।\n\nथप जानकारीको लागि, आफ्नो प्रशासकसँग सम्पर्क राख्नुहोस्।\n\nतपाईँ VPN सँग पनि जडित हुनुहुन्छ, जसले तपाईँको नेटवर्क गतिविधि अनुगमन गर्न सक्छ।"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँका नेटवर्क गतिविधिको अनुगमन गर्न सक्छ।"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> मा जोडिनुभएको छ जसले इमेल, अनुप्रयोग र वेबसाइटहरू लगायतको तपाईंको  व्यक्तिगत नेटवर्क सम्बन्धी गतिविधिको अनुगमन गर्न सक्छ।"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि, आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> सँग पनि जडित हुनुहुन्छ, जसले तपाईँको व्यक्तिगत नेटवर्क गतिविधि अनुगमन गर्न सक्छ।"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तार गर्नुहोस्"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संक्षिप्त पार्नुहोस्"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"पर्दा राखेका छ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"बुझेँ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"धन्यवाद पर्दैन"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"सक्रिय"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"निष्क्रिय"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"सशक्त सूचना नियन्त्रणहरू मार्फत तपाईँ अनुप्रयाेगका सूचनाहरूका लागि ० देखि ५ सम्मको महत्व सम्बन्धी स्तर सेट गर्न सक्नुहुन्छ। \n\n"<b>"स्तर ५"</b>" \n- सूचनाको सूचीको माथिल्लो भागमा देखाउने \n- पूर्ण स्क्रिनमा अवरोधका लागि अनुमति दिने \n- सधैँ चियाउने \n\n"<b>"स्तर ४"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- सधैँ चियाउने \n\n"<b>"स्तर ३"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n\n"<b>"स्तर २"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने र कम्पन नगर्ने \n\n"<b>"स्तर १"</b>" \n- पूर्ण स्क्रिनमा अवरोध रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने वा कम्पन नगर्ने \n- लक स्क्रिन र वस्तुस्थिति पट्टीबाट लुकाउने \n- सूचनाको सूचीको तल्लो भागमा देखाउने \n\n"<b>"स्तर ०"</b>" \n- अनुप्रयोगका सबै सूचनाहरूलाई रोक्ने"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचनाहरू"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"तपाईंले अबदेखि यी सूचनाहरू प्राप्त गर्नुहुने छैन।"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"निम्न कुराका लागि <xliff:g id="APP">%s</xliff:g> का सूचनाहरू"</string>
+    <string name="min_importance" msgid="7559703098688382595">"न्यून"</string>
+    <string name="low_importance" msgid="6891335321576225228">"मध्यम"</string>
+    <string name="default_importance" msgid="6400766013567512061">"उच्च"</string>
+    <string name="high_importance" msgid="730741630855788381">"जरुरी"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"कुनै आवाज ननिकाल्ने वा दृश्य सम्बन्धी अवरोध नपुर्याउने"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"मौन रूपमा देखाउने"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"आवाज निकाल्ने"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"आवाज निकाल्ने र स्क्रिनमा पपअप देखाउने"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
     <string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचनाका लागि नियन्त्रणहरू"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 9c6fbbd..cfb030d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Vergrendelingsscherm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Instellingen"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overzicht."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Vergrendelingsscherm voor werk"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Sluiten"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi uitgeschakeld."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nachtverlichting"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Geen recente items"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Je hebt alles gewist"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verticaal splitsen"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Aangepast splitsen"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Verbinding met VPN verbreken"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Je apparaat wordt beheerd door <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> gebruikt <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> om je apparaat te beheren."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Je beheerder kan instellingen, zakelijke toegang, apps, aan je apparaat gekoppelde gegevens en de locatiegegevens van je apparaat controleren en beheren."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Meer informatie"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Je bent verbonden met <xliff:g id="VPN_APP">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden gecontroleerd."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN-instellingen openen"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Je beheerder heeft netwerkregistratie ingeschakeld, waarmee verkeer op je apparaat wordt bijgehouden.\n\nNeem voor meer informatie contact op met je beheerder."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Je hebt een app toestemming gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan je netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie.\n\nU bent ook verbonden met een VPN waarmee je netwerkactiviteit kan worden gecontroleerd."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Het apparaat blijft vergrendeld totdat u het handmatig ontgrendelt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Sneller meldingen ontvangen"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Uitvouwen"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Samenvouwen"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Scherm is vastgezet"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Overzicht en houd dit vast om het scherm los te maken."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ik snap het"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, bedankt"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> verbergen?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aan"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Uit"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Met beheeropties voor meldingen met betrekking tot stroomverbruik kun je een belangrijkheidsniveau van 0 tot 5 instellen voor de meldingen van een app. \n\n"<b>"Niveau 5"</b>" \n- Boven aan de lijst met meldingen weergeven \n- Onderbreking op volledig scherm toestaan \n- Altijd korte weergave \n\n"<b>"Niveau 4"</b>" \n- Geen onderbreking op volledig scherm \n- Altijd korte weergave \n\n"<b>"Niveau 3"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n\n"<b>"Niveau 2"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n\n"<b>"Niveau 1"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n- Verbergen op vergrendelingsscherm en statusbalk \n- Onder aan de lijst met meldingen weergeven \n\n"<b>"Niveau 0"</b>" \n- Alle meldingen van de app blokkeren"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Meldingen"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Je ontvangt deze meldingen niet meer."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-meldingen voor"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Laag"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Gemiddeld"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hoog"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgent"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Geen geluid of visuele onderbreking"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Zonder geluid weergeven"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Geluid laten horen"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Geluid laten horen en op het scherm weergeven"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Beheeropties voor <xliff:g id="APP_NAME">%1$s</xliff:g>-meldingen"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3f0915b..0ec824d 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ਲੌਕ ਸਕ੍ਰੀਨ।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ਰੂਪ-ਰੇਖਾ।"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ਕਾਰਜ-ਸਥਾਨ ਲੌਕ ਸਕ੍ਰੀਨ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ਬੰਦ ਕਰੋ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi ਬੰਦ ਕੀਤਾ।"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ਕੰਮ ਮੋਡ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"ਰਾਤਰੀ ਲਾਈਟ"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ਤੁਸੀਂ ਸਭ ਕੁਝ ਸਾਫ਼ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਣਕਾਰੀ"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ਹੌਰੀਜ਼ੌਂਟਲ ਸਪਲਿਟ"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ਵਰਟੀਕਲ ਸਪਲਿਟ"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ਕਸਟਮ ਸਪਲਿਟ"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ਚਾਰਜ ਹੋਇਆ"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ਤੁਹਾਡੀ ਡੀਵਾਈਸ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਦੇ ਪ੍ਰਬੰਧਨ ਲਈ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ।"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"ਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਅਤੇ ਉਸਦੀ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਸਬੰਧੀ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਾਂ, ਡੈਟੇ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ।"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"ਹੋਰ ਜਾਣੋ"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ਤੁਸੀਂ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਕਿ ਤੁਹਾਡੀ ਡੀਵਾਈਸ \'ਤੇ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"ਤੁਸੀਂ ਇੱਕ ਐਪ ਨੂੰ ਇੱਕ VPN ਕਨੈਕਸ਼ਨ ਸੈਟ ਅਪ ਕਰਨ ਦੀ ਅਨੁਮਤੀ ਦਿੱਤੀ ਹੈ।\n\nਇਹ ਐਪ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਅਤੇ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ, ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ ਸਮੇਤ।"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਈਮੇਲ, ਐਪਸ, ਅਤੇ ਵੈੱਬਪੰਨੇ ਸੰਤੇ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰਨ ਦੇ ਸਮਰੱਥ ਹੈ।\n\nਵਧੇਰੇ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।\n\nਤੁਸੀਂ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋ, ਜੋ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਦੁਆਰਾ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ। ਇਹ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ।"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ਡੀਵਾਈਸ ਲੌਕ ਰਹੇਗੀ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਮੈਨੂਅਲੀ ਅਨਲੌਕ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ਤੇਜ਼ੀ ਨਾਲ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ਨਸ਼ਟ ਕਰੋ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ਸਮਝ ਲਿਆ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ਕੀ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ਨੂੰ ਲੁਕਾਉਣਾ ਹੈ?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ਚਾਲੂ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ਬੰਦ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ਪਾਵਰ ਸੂਚਨਾ ਕੰਟਰੋਲਾਂ ਨਾਲ, ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਦੀਆਂ ਸੂਚਨਾਵਾਂ ਲਈ ਮਹੱਤਤਾ ਪੱਧਰ ਨੂੰ 0 ਤੋਂ 5 ਤੱਕ ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। \n\n"<b>"ਪੱਧਰ 5"</b>" \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਦੀ ਆਗਿਆ ਦਿਓ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 4"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 3"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 2"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n- ਕਦੇ ਵੀ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n\n"<b>"ਪੱੱਧਰ 1"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n- ਕਦੇ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n- ਲੌਕ ਸਕ੍ਰੀਨ ਅਤੇ ਸਥਿਤੀ ਪੱਟੀ ਤੋਂ ਲੁਕਾਓ \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 0"</b>" \n- ਐਪ ਤੋਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬਲੌਕ ਕਰੋ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ਸੂਚਨਾਵਾਂ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ਤੁਸੀਂ ਹੁਣ ਇਹ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰੋਂਗੇ।"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ਇਸ ਦੇ ਲਈ <xliff:g id="APP">%s</xliff:g> ਸੂਚਨਾਵਾਂ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ਘੱਟ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ਔਸਤ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ਉੱਚ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ਜ਼ਰੂਰੀ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਦ੍ਰਿਸ਼ਟਾਂਤਕ ਰੁਕਾਵਟ ਨਹੀਂ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ਚੁੱਪਚਾਪ ਵਿਖਾਓ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ਧੁਨੀ ਵਜਾਓ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ਧੁਨੀ ਵਜਾਓ ਅਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਖਾਓ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index abaf4bc..4926e30 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ekran blokady."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ustawienia"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Przegląd."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ekran blokady wyświetlany podczas działania"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zamknij"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi wyłączone."</string>
@@ -326,6 +325,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Tryb pracy"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Podświetlenie nocne"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Brak ostatnich elementów"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Wszystko zostało wyczyszczone"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
@@ -339,6 +344,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podziel pionowo"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podziel niestandardowo"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
@@ -419,20 +434,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Rozłącz z VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Twoim urządzeniem zarządza <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> używa aplikacji <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> do zarządzania Twoim urządzeniem."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administrator może monitorować ustawienia, dostęp firmowy, aplikacje, dane dotyczące urządzenia i lokalizacji oraz nimi zarządzać."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">"  "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Więcej informacji"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Łączysz się z aplikacją <xliff:g id="VPN_APP">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">"  "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otwórz ustawienia VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administrator włączył rejestrowanie sieciowe, które pozwala monitorować ruch na Twoim urządzeniu.\n\nAby uzyskać więcej informacji, skontaktuj się z administratorem."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Aplikacja otrzymała od Ciebie uprawnienia do konfigurowania połączenia VPN.\n\nMoże ona monitorować Twoją aktywność na urządzeniu i w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nSkontaktuj się z nim, by dowiedzieć się więcej.\n\nMasz też połączenie z siecią VPN, która może monitorować Twoją aktywność w sieci."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Masz połączenie z aplikacją <xliff:g id="APPLICATION">%1$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci, w tym e-maile, aplikacje i strony internetowe."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nAby dowiedzieć się więcej, skontaktuj się z administratorem."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Twoim profilem do pracy zarządza <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci związaną z pracą, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją prywatną aktywność w sieci."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Urządzenie pozostanie zablokowane, aż odblokujesz je ręcznie"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Szybszy dostęp do powiadomień"</string>
@@ -444,10 +463,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozwiń"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zwiń"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran jest przypięty"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, dziękuję"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +531,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Wł."</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Wył."</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Dzięki zaawansowanym ustawieniom możesz określić poziom ważności powiadomień z aplikacji w skali od 0 do 5. \n\n"<b>"Poziom 5"</b>" \n– Pokazuj u góry listy powiadomień \n– Zezwalaj na powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 4"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 3"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n\n"<b>"Poziom 2"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n\n"<b>"Poziom 1"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n– Ukrywaj na ekranie blokady i pasku stanu \n– Pokazuj u dołu listy powiadomień \n\n"<b>"Poziom 0"</b>" \n– Blokuj wszystkie powiadomienia aplikacji"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Powiadomienia"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nie będziesz już otrzymywać tych powiadomień."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Powiadomienia aplikacji <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niska"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Średnia"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Wysoka"</string>
+    <string name="high_importance" msgid="730741630855788381">"Pilna"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Brak dźwięku i komunikatów wizualnych"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Pokazuj dyskretnie"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Sygnalizacja dźwiękiem"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Sygnalizacja dźwiękiem i wyświetlenie komunikatu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> – ustawienia powiadomień"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 70618c9..c89cdc9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Tela de bloqueio."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configurações"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visão geral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Tela de bloqueio de trabalho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"O Wi-Fi foi desativado."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Modo noturno"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Seu dispositivo é gerenciado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> usa <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para gerenciar seu dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"O admin. pode monitorar e gerenciar config., acesso corporativo, apps, dados associados ao dispos. e as info. de local do dispos."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saber mais"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Você está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configurações de VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Seu administrador ativou o registro de rede, que monitora o tráfego no seu dispositivo.\n\nPara ver mais informações, entre em contato com o administrador."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Você deu permissão para um app configurar uma conexão VPN.\n\nEsse app pode monitorar seu dispositivo e a atividade na rede, incluindo e-mails, apps e websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara mais informações, entre em contato com seu administrador.\n\nVocê também está conectado a uma VPN, a qual pode monitorar suas atividades de rede."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Receba notificações mais rápido"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ativado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Você deixará de receber essas notificações."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificações do app <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Média"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sem som ou interrupção visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir som"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e exibir na tela"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7102c64..5f87c12 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ecrã de bloqueio."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Definições"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visão geral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ecrã de bloqueio de trabalho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi desligado."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz noturna"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Limpou tudo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desligar VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"O seu dispositivo é gerido pelo <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"A <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> utiliza o <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para gerir o seu dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"O administ. pode monitorizar e gerir definições, acesso empresarial, aplic. e dados associados ao dispositivo, bem como inf. de localiz. do disp."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saiba mais"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Está ligado à rede <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode monitorizar a sua atividade de rede, incluindo emails, aplicações e Websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir as definições de VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"O seu administrador ativou os registos de rede, que monitorizam o tráfego no seu dispositivo.\n\nPara mais informações, contacte o administrador."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Concedeu autorização a uma aplicação para configurar uma ligação VPN.\n\nEsta aplicação pode monitorizar a atividade do dispositivo e da rede, incluindo emails, aplicações e Websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nO seu administrador pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador.\n\nAlém disso, está ligado a uma VPN, que pode monitorizar a atividade da rede."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede, incluindo emails, aplicações e Websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Está ligado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Está ligado ao <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorizar a atividade da rede pessoal, incluindo emails, aplicações e Websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nPara obter mais informações, contacte o administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"O seu perfil de trabalho é gerido por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Está ligado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Websites.\n\nTambém está ligado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até ser desbloqueado manualmente"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Receber notificações mais rapidamente"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Reduzir"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"O ecrã está fixado"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Vista geral para soltar."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Compreendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ativado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com os controlos de notificações do consumo de energia, pode definir um nível de importância de 0 a 5 para as notificações de aplicações. \n\n"<b>"Nível 5"</b>" \n- Mostrar no início da lista de notificações \n- Permitir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre \n\n"<b>"Nível 4"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre\n\n"<b>"Nível 3"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n\n"<b>"Nível 2"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n- Ocultar do ecrã de bloqueio e da barra de estado \n- Mostrar no fim da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações da aplicação"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Já não recebe estas notificações."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificações da aplicação <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Média"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sem interrupção sonora ou visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar silenciosamente"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir som"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e aparecer no ecrã"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlos de notificações do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 70618c9..c89cdc9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Tela de bloqueio."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configurações"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visão geral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Tela de bloqueio de trabalho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"O Wi-Fi foi desativado."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Modo noturno"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Desconectar VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Seu dispositivo é gerenciado por <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> usa <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> para gerenciar seu dispositivo."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"O admin. pode monitorar e gerenciar config., acesso corporativo, apps, dados associados ao dispos. e as info. de local do dispos."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Saber mais"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Você está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Abrir configurações de VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Seu administrador ativou o registro de rede, que monitora o tráfego no seu dispositivo.\n\nPara ver mais informações, entre em contato com o administrador."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Você deu permissão para um app configurar uma conexão VPN.\n\nEsse app pode monitorar seu dispositivo e a atividade na rede, incluindo e-mails, apps e websites."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSeu administrador pode monitorar suas atividades de rede, incluindo e-mails, apps e websites.\n\nPara mais informações, entre em contato com seu administrador.\n\nVocê também está conectado a uma VPN, a qual pode monitorar suas atividades de rede."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade na rede, incluindo e-mails, apps e websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Você está conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode monitorar sua atividade pessoal na rede, incluindo e-mails, apps e websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nPara ver mais informações, entre em contato com seu administrador."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ele está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional na rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal na rede."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Receba notificações mais rápido"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ativado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Você deixará de receber essas notificações."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificações do app <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Média"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sem som ou interrupção visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir som"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e exibir na tela"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2544849..66f7bde 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -188,8 +188,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ecranul de blocare."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Setări"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Vizualizare generală"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ecran de blocare pentru serviciu"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Închideți"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Conexiunea prin Wi-Fi este dezactivată."</string>
@@ -326,6 +325,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modul de lucru"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Lumină de noapte"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Niciun element recent"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ați șters tot"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
@@ -339,6 +344,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divizare pe verticală"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divizare personalizată"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Încărcată"</string>
@@ -419,20 +434,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Deconectați rețeaua VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Dispozitivul dvs. este gestionat de <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> folosește <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> pentru a vă gestiona dispozitivul."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administratorul dvs. poate monitoriza și gestiona setările, accesul la nivelul companiei, aplicațiile, datele asociate cu dispozitivul dvs. și informațiile despre locația dispozitivului."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Aflați mai multe"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"V-ați conectat la aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Deschideți Setări VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administratorul dvs. a activat înregistrarea în jurnal pentru rețea, funcție ce monitorizează traficul de pe dispozitivul dvs.\n\nPentru mai multe informații, contactați administratorul."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Ați acordat unei aplicații permisiunea de a configura o conexiune VPN.\n\nAceastă aplicație poate monitoriza activitatea de pe dispozitiv și în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratorul poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul.\n\nDe asemenea, sunteți conectat(ă) la o rețea VPN, care vă poate monitoriza activitatea în rețea."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețea, inclusiv e-mailurile, aplicațiile și site-urile."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Sunteți conectat(ă) la <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală, inclusiv e-mailurile, aplicațiile și site-urile."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"V-ați conectat la aplicația <xliff:g id="APPLICATION">%1$s</xliff:g>, care vă poate monitoriza activitatea personală în rețea, inclusiv e-mailurile, aplicațiile și site-urile accesate."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nPentru mai multe informații, contactați administratorul."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile.\n\nDe asemenea, sunteți conectat(ă) la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Dispozitivul va rămâne blocat până când îl deblocați manual"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Obțineți notificări mai rapid"</string>
@@ -444,10 +463,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Extindeți"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Restrângeți"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ecranul este fixat"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Am înțeles"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nu, mulțumesc"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +531,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activate"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Dezactivate"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Folosind comenzile de gestionare a notificărilor, puteți să setați un nivel de importanță de la 0 la 5 pentru notificările unei aplicații. \n\n"<b>"Nivelul 5"</b>" \n– Se afișează la începutul listei de notificări \n– Se permite întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 4"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 3"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n\n"<b>"Nivelul 2"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n\n"<b>"Nivelul 1"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n– Se ascunde în ecranul de blocare și în bara de stare \n– Se afișează la finalul listei de notificări \n\n"<b>"Nivelul 0"</b>" \n– Se blochează toate notificările din aplicație"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificări"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nu veți mai primi aceste notificări."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificări <xliff:g id="APP">%s</xliff:g> pentru"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Scăzută"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Medie"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Ridicată"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgentă"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Fără sunet sau întrerupere vizuală"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Se afișează fără sunet"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Se emite un sunet"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Se emite un sunet și se evidențiază pe ecran"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Opțiuni privind notificările pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index aa7695a..0571e8d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заблокированный экран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Настройки"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Обзор."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Заблокировано"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрыть"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Модуль Wi-Fi отключен."</string>
@@ -328,6 +327,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рабочий режим"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ночной режим"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Недавних приложений нет"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы очистили всё"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
@@ -341,6 +346,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
@@ -421,20 +436,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Отключить VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Этим устройством управляет приложение \"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>\""</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Компания \"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>\" управляет устройством с помощью приложения \"<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>\""</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Администратор контролирует настройки, приложения, доступ к ресурсам компании, связанные с устройством данные и передачу геоданных."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Подробнее…"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Запущено приложение \"<xliff:g id="VPN_APP">%1$s</xliff:g>\". Оно может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и сайтами."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Открыть настройки VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Администратор включил ведение сетевого журнала, чтобы отслеживать трафик на вашем устройстве.\n\nДля получения подробной информации обращайтесь к администратору."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Вы разрешили приложению подключаться к сети VPN.\n\nОно может отслеживать ваши действия на устройстве и в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Вашим корпоративным профилем управляет <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа подробностями обратитесь к нему.\n\nУстройство также подключено к сети VPN, в которой возможно отслеживание ваших действий."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"Сеть VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в Интернете (выполняемые в личном профиле), включая работу с электронной почтой, приложениями и веб-сайтами."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Запущено приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\", которое может отслеживать ваши действия в сети, включая работу с электронной почтой, приложениями и веб-сайтами."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nЗа дополнительной информацией обратитесь к своему администратору."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим рабочим профилем управляет \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>\" может отслеживать ваши действия в Интернете, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nПриложение \"<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>\" может отслеживать ваши действия в Интернете, выполняемые в личном профиле."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Устройство необходимо будет разблокировать вручную"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Быстрый доступ к уведомлениям"</string>
@@ -446,10 +465,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Развернуть"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свернуть"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Блокировка в приложении включена"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Обзор\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ОК"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Нет, спасибо"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Скрыть параметр \"<xliff:g id="TILE_LABEL">%1$s</xliff:g>\"?"</string>
@@ -516,28 +533,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Включено"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Отключено"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"С помощью этой функции вы можете устанавливать уровень важности уведомлений от 0 до 5 для каждого приложения.\n\n"<b>"Уровень 5"</b>\n"‒ Помещать уведомления в начало списка.\n‒ Показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 4\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 3\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\nУровень 2\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\nУровень 1\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\n‒ Не показывать на экране блокировки и в строке состояния.\n‒ Помещать уведомления в конец списка.\nУровень 0\n"<b></b>\n"‒ Блокировать все уведомления приложения."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Уведомления"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Вы больше не будете получать эти уведомления."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>: уведомления"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Низкий приоритет"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средний приоритет"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Высокий приоритет"</string>
+    <string name="high_importance" msgid="730741630855788381">"Срочно"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без уведомлений"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Без звука"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Звук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Звук и всплывающее окно"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Управление уведомлениями (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 4b540b9..5987fe5 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"අගුළු තිරය."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"සැකසීම්"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"දළ විශ්ලේෂණය."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"කාර්යාල අගුලු තිරය"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"වසන්න"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi අක්‍රියයි."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"වැඩ ප්‍රකාරය"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"රාත්‍රී ආලෝකය"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"මෑත අයිතම නැත"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ඔබ සියලු දේ හිස් කර ඇත"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"යෙදුම් තොරතුරු"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"සිරස්ව වෙන් කරන්න"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"අභිමත ලෙස වෙන් කරන්න"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"අරෝපිතයි"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN විසන්ධි කරන්න"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"ඔබගේ උපාංගය <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> මගින් කළමනාකරණය කෙරේ."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ඔබගේ උපාංගය කළමනාකරණය කිරීමට <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> භාවිත කරයි."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"ඔබේ උපාංගය සමඟ සම්බන්ධිත සැකසීම්, සංස්ථාපිත ප්‍රවේශය, යෙදුම්, දත්ත, සහ ඔබගේ උපාංගයේ ස්ථාන තොරතුරු නිරීක්ෂණය සහ කළමනාකරණය කිරීමට ඔබගේ පරිපාලකට හැකිය."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"තව දැන ගන්න"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි <xliff:g id="VPN_APP">%1$s</xliff:g>, වෙත ඔබ සම්බන්ධ වී ඇත."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN සැකසීම් විවෘත කරන්න"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"ඔබගේ පරිපාලක ඔබගේ උපාංගය මත තදබදය නිරීක්ෂණය කරන, ජාල ඇතුළු වීම ක්‍රියාත්මක කර ඇත.\n\nවැඩිදුර තොරතුරු සඳහා ඔබේ පරිපාලක අමතන්න."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"ඔබ VPN සම්බන්ධතාවක් පිහිටුවීමට යෙදුමකට අවසරයක් දී ඇත.\n\nමෙම යෙදුමට ඔබේ ඊ-තැපැල්, යෙදුම්, සහ වෙබ් අඩවි ඇතුළු, ඔබගේ උපාංග සහ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකිය."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"ඔබේ කාර්ය පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි.\n\nඔබේ පරිපාලකට ඔබේ ඊ-තැපැල්, යෙදුම්, සහ ආරක්ෂාකාරී වෙබ් අඩවි ඇතුළු, ඔබගේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකියාව ඇත.\n\nවැඩිදුර තොරතුරු සඳහා, ඔබගේ පරිපාලක අමතන්න.\n\nඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කිරීමට හැකි VPN සම්බන්ධතාවයකටද, ඔබ සම්බන්ධව ඇත."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%1$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION">%2$s</xliff:g> වෙත ඔබ සම්බන්ධ වී ඇත.\n\nවැඩිදුර විස්තර සඳහා, ඔබේ පරිපාලක අමතන්න."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. එය ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, වෙත ඔබ සම්බන්ධ වී ඇත.\n\nඔබ ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> වෙතද සම්බන්ධ වී ඇත."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ඔබ අතින් අගුළු අරින තුරු උපකරණය අගුළු වැටි තිබේ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"දැනුම්දීම් ඉක්මනින් ලබාගන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b6b5361..9ace153 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Uzamknutá obrazovka"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nastavenia"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Prehľad"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Uzamknutá obrazovka pracovného profilu"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zavrieť"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Pripojenie Wi-Fi je vypnuté."</string>
@@ -328,6 +327,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovný režim"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nočný režim"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Žiadne nedávne položky"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vymazali ste všetko"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
@@ -341,6 +346,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Rozdeliť zvislé"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Rozdeliť vlastné"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nabitá"</string>
@@ -421,20 +436,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Odpojiť sieť VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Vaše zariadenie spravuje aplikácia <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> spravuje vaše zariadenie pomocou aplikácie <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Správca môže sledovať a spravovať nastavenia, firemný prístup, aplikácie a údaje súvisiace s týmto zariadením vrátane informácií o polohe vášho zariadenia."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Ďalšie informácie"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Ste pripojený/-á k aplikácii <xliff:g id="VPN_APP">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Otvoriť Nastavenia pripojenia VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Váš správca aktivoval zapisovanie do denníka siete, ktoré sleduje premávku na vašom zariadení.\n\nĎalšie informácie vám poskytne správca."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Určitej aplikácii ste udelili povolenie nastaviť pripojenie VPN.\n\nTáto aplikácia môže sledovať vaše zariadenie a aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSprávca môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nĎalšie informácie získate od svojho správcu.\n\nSte tiež pripojený/-á k sieti VPN, ktorá môže sledovať vašu aktivitu v sieti."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nĎalšie informácie získate od svojho správcu."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok.\n\nSte tiež pripojený/-á k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Zariadenie zostane uzamknuté, dokým ho ručne neodomknete."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Získavať upozornenia rýchlejšie"</string>
@@ -446,10 +465,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbaliť"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zbaliť"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je pripnutá"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Dobre"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, vďaka"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +533,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Zapnuté"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuté"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Pomocou ovládacích prvkov zobrazovania upozornení môžete nastaviť pre upozornenia aplikácie úroveň dôležitosti od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazovať v hornej časti zoznamu upozornení. \n– Povoliť prerušenia na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 4"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 3"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n\n"<b>"Úroveň 2"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n\n"<b>"Úroveň 1"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n– Skryť na uzamknutej obrazovke a v stavovom riadku. \n– Zobraziť v dolnej časti zoznamu upozornení. \n\n"<b>"Úroveň 0"</b>" \n– Blokovať všetky upozornenia z aplikácie."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Upozornenia"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Takéto upozornenia už nebudete dostávať."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Upozornenia aplikácie <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nízka"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Stredná"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Vysoká"</string>
+    <string name="high_importance" msgid="730741630855788381">"Neodkladná"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvuku a vizuálneho vyrušenia"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Zobraziť bez zvukov"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Vydať zvukový signál"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Vydať zvukový signál a vyskočiť na obrazovku"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Ovládacie prvky pre upozornenia z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index b9a8266..ec26b53 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaklenjen zaslon"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nastavitve"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaklenjen zaslon delovnega profila"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zapri"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi je izklopljen."</string>
@@ -328,6 +327,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način za delo"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nočna svetloba"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Ni nedavnih elementov"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vse te počistili"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
@@ -341,6 +346,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Razdeli navpično"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Razdeli po meri"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
@@ -421,20 +436,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Prekini povezavo z VPN-jem"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Napravo upravlja aplikacija <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> uporablja aplikacijo <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> za upravljanje naprave."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Skrbnik lahko nadzira in upravlja nastavitve, dostop za podjetje, aplikacije, z napravo povezane podatke in podatke o lokaciji."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Več o tem"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Povezani ste z aplikacijo <xliff:g id="VPN_APP">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Odpri nastavitve omrežja VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Skrbnik je vklopil beleženje omrežnega prometa, ki nadzoruje promet v napravi.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Aplikaciji ste dovolili vzpostavitev povezave VPN.\n\nTa aplikacija lahko nadzira napravo in omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nSkrbnik lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika.\n\nPovezani ste tudi z omrežjem VPN, ki lahko nadzira omrežno dejavnost."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nČe želite več informacij, se obrnite na skrbnika."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Naprava bo ostala zaklenjena, dokler je ročno ne odklenete."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Hitrejše prejemanje obvestil"</string>
@@ -446,10 +465,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Razširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Strni"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je pripet"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za pregled."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Razumem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +533,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Vklopljeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izklopljeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"S kontrolniki za pomebnost obvestila je mogoče za obvestila aplikacije nastaviti stopnjo pomembnosti od 0 do 5. \n\n"<b>"Stopnja 5"</b>" \n– Prikaz na vrhu seznama obvestil \n– Omogočanje prekinitev v celozaslonskem načinu \n– Vedno prikaži hitre predoglede \n\n"<b>"Stopnja 4"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Vedno prikaži hitre predoglede \n\n"<b>"Stopnja 3"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n\n"<b>"Stopnja 2"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n– Nikoli ne uporabi zvoka in vibriranja \n\n"<b>"Stopnja 1"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n– Nikoli ne uporabi zvoka in vibriranja \n– Skrivanje na zaklenjenem zaslonu in v vrstici stanja \n– Prikaz na dnu seznama obvestil \n\n"<b>"Stopnja 0"</b>" \n– Blokiranje vseh obvestil aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obvestila"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Teh obvestil ne boste več prejemali."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obvestila iz aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nizka"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednja"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoka"</string>
+    <string name="high_importance" msgid="730741630855788381">"Nujno"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Brez zvočne ali vizualne prekinitve"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikaži brez zvoka"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Predvajaj zvok"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Predvajaj zvok in prikaži na zaslonu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
     <string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolniki obvestil za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index d54b5a3..009b0be 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ekrani i kyçjes."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Cilësimet"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Përmbledhja."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ekrani i kyçjes së punës"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Mbylle"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi është i çaktivizuar."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modaliteti i punës"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Drita e natës"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Nuk ka asnjë artikull të fundit"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"I ke pastruar të gjitha"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacioni i aplikacionit"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Ndaje horizontalisht"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ndaj vertikalisht"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ndaj të personalizuarën"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"I ngarkuar"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Shkëput VPN-në"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Pajisja jote menaxhohet nga <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> përdor <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> për të menaxhuar pajisjen tënde."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administratori yt mund të monitorojë dhe të menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat në lidhje me pajisjen si dhe informacionet e vendndodhjes së pajisjes tënde."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Mëso më shumë"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Je i lidhur me aplikacionin <xliff:g id="VPN_APP">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Hap cilësimet e VPN-së"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administratori yt ka aktivizuar regjistrimin e rrjetit, i cili monitoron trafikun në pajisjen tënde.\n\nPër më shumë informacione, kontakto me administratorin."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"I dhe leje një aplikacioni që të konfigurojë një lidhje VPN.\n\nKy aplikacion mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë mail-at, aplikacionet dhe faqet e internetit.\n\nPër më shumë informacion, kontakto me administratorin tënd.\n\nJe i lidhur edhe me një VPN, që mund të monitorojë aktivitetin tënd të rrjetit."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd në rrjet përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Je i lidhur me aplikacionin <xliff:g id="APPLICATION">%1$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ai është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, përfshirë mailet, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Pajisje do të qëndrojë e kyçur derisa ta shkyçësh manualisht"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Merr njoftime më shpejt"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zgjeroje"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Mbylle"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrani u gozhdua"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Të fshihet <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aktiv"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Joaktiv"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Me kontrollet e njoftimit të energjisë, mund të caktosh një nivel rëndësie nga 0 në 5 për njoftimet e një aplikacioni. \n\n"<b>"Niveli 5"</b>" \n- Shfaq në krye të listës së njoftimeve \n- Lejo ndërprerjen e ekranit të plotë \n- Gjithmonë shfaq shpejt \n\n"<b>"Niveli 4"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Gijthmonë shfaq shpejt \n\n"<b>"Niveli 3"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n\n"<b>"Niveli 2"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull dhe dridhje \n\n"<b>"Niveli 1"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull ose dridhje \n- Fshih nga ekrani i kyçjes dhe shiriti i statusit \n- Shfaq në fund të listës së njoftimeve \n\n"<b>"Niveli 0"</b>" \n- Blloko të gjitha njoftimet nga aplikacioni"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Njoftime"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Këto njoftime nuk do t\'i marrësh më."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Njoftimet e <xliff:g id="APP">%s</xliff:g> për"</string>
+    <string name="min_importance" msgid="7559703098688382595">"I ulët"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Mesatar"</string>
+    <string name="default_importance" msgid="6400766013567512061">"I lartë"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgjent"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Asnjë tingull apo ndërprerje vizuale"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Shfaq në heshtje"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Bëj tingull"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Bëj një tingull dhe shfaq në ekran"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
     <string name="notification_done" msgid="5279426047273930175">"U krye"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrollet e njoftimeve të <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 727c01e..a82ff68 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Закључани екран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Подешавања"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Преглед."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Закључани екран за посао"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Затвори"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi је искључен."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим рада"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ноћно светло"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Нема недавних ставки"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Обрисали сте све"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Подели вертикално"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Прилагођено дељење"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Прекини везу са VPN-ом"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Уређајем управља <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> користи <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> за управљање уређајем."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Администратор може да надгледа подешавања, корпоративни приступ, апликације, податке повезане са уређајем и информације о локацији уређаја, као и да управља њима."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Сазнајте више"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Повезани сте са апликацијом <xliff:g id="VPN_APP">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Отворите подешавања VPN-а"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Администратор је укључио евидентирање мреже, које прати саобраћај на уређају.\n\nКонтактирајте администратора за више информација."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Дали сте дозволу апликацији да подешава VPN везу.\n\nТа апликација може да надгледа активности на уређају и мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдминистратор може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора.\n\nПовезани сте и на VPN, који може да надгледа активности на личној мрежи."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Уређај ће остати закључан док га не откључате ручно"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Брже добијајте обавештења"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Скупи"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран је закачен"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Преглед да бисте га откачили."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Преглед да бисте га откачили."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Важи"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, хвала"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Желите ли да сакријете <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Укључено"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Искључено"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Помоћу напредних контрола за обавештења можете да подесите ниво важности од 0. до 5. за обавештења апликације. \n\n"<b>"5. ниво"</b>" \n– Приказују се у врху листе обавештења \n- Дозволи прекид режима целог екрана \n– Увек завируј \n\n"<b>"4. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Увек завируј \n\n"<b>"3. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n\n"<b>"2. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n\n"<b>"1. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n– Сакриј на закључаном екрану и статусној траци \n– Приказују се у дну листе обавештења \n\n"<b>"0. ниво"</b>" \n– Блокирај сва обавештења из апликације"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Обавештења"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Више нећете да добијате ова обавештења."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Обавештења апликације <xliff:g id="APP">%s</xliff:g> за"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ниско"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средње"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Високо"</string>
+    <string name="high_importance" msgid="730741630855788381">"Хитно"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звучног сигнала или визуелног обавештења"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Приказује се без звучног сигнала"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Емитује се звучни сигнал"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Емитује се звучни сигнал и приказује се на екрану"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроле обавештења за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a04a761..8c778d0 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låsskärm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Inställningar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Översikt."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Låsskärm för arbete"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Stäng"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi har inaktiverats."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbetsläge"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattljus"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Listan med de senaste åtgärderna är tom"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har tömt listan"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Koppla från VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Enheten hanteras av <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> hanterar enheten med hjälp av <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administratören kan övervaka och hantera inställningar, företagsåtkomst, appar, data med koppling till enheten och enhetens plats."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Läs mer"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Du är ansluten till <xliff:g id="VPN_APP">%1$s</xliff:g> som kan övervaka din aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Öppna VPN-inställningar"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administratören har aktiverat nätverksloggning, vilken övervakar trafik på enheten.\n\nKontakta administratören om du vill veta mer."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Du har gett en app behörighet att upprätta en VPN-anslutning.\n\nAppen kan bevaka aktivitet på enheten och nätverket, inklusive e-post, appar och webbplatser."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratören kan bevaka aktiviteten på nätverket, inklusive e-post, appar och webbplatser.\n\nKontakta administratören för mer information.\n\nDu är även ansluten till ett VPN-nätverk som kan bevaka aktiviteten på nätverket."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan bevaka din privata aktivitet på nätverket, inklusive e-post, appar och webbplatser."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Du är ansluten till <xliff:g id="APPLICATION">%1$s</xliff:g> som kan övervaka din privata aktivitet på nätverket, inklusive e-postmeddelanden, appar och webbplatser."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nKontakta administratören för mer information."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan hantera aktivitet på arbetsplatsens nätverk, inklusive e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan hantera privat aktivitet på nätverket."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten förblir låst tills du låser upp den manuellt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Få aviseringar snabbare"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utöka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Komprimera"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skärmen har fästs"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Översikt om du vill lossa skärmen."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Skärmen visas tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tack"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vill du dölja <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Av"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"På"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med aviseringsinställningarna kan du ange prioritetsnivå från 0 till 5 för aviseringar från en app. \n\n"<b>"Nivå 5"</b>" \n– Visa högst upp i aviseringslistan\n– Tillåt avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 4"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 3"</b>" \n- Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n\n"<b>"Nivå 2"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n\n"<b>"Nivå 1"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n– Visa inte på låsskärmen och i statusfältet \n– Visa längst ned i aviseringslistan \n\n"<b>"Nivå 0"</b>" \n– Blockera alla aviseringar från appen"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Aviseringar"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Inga fler aviseringar av det här slaget visas."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Aviseringar från <xliff:g id="APP">%s</xliff:g> –"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Låg"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Medelhög"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hög"</string>
+    <string name="high_importance" msgid="730741630855788381">"Brådskande"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Spela inte upp ljud och visa inte"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Visa utan ljud"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Spela upp ljud"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Spela upp ljud och visa på skärmen"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klar"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-aviseringar"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 49c1860..28ecc50 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Skrini iliyofungwa."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Mipangilio"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Muhtasari."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Skrini iliyofungwa ya kazini"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Funga"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi imezimwa."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Hali ya kazi"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Mwanga wa Usiku"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Hakuna vipengee vya hivi karibuni"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Umeondoa vipengee vyote"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Ondoa VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Kifaa chako kinadhibitiwa na <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> inatumia <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> kudhibiti kifaa chako."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Msimamizi wako anaweza kufuatilia na kudhibiti mipangilio, ufikiaji wa mashirika, programu, data inayohusiana na kifaa chako na maelezo ya eneo la kifaa chako."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Pata maelezo zaidi"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Umeunganishwa kwenye <xliff:g id="VPN_APP">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Fungua Mipangilio ya VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Msimamizi wako amewasha kumbukumbu ya kuingia mtandaoni ambayo huchunguza trafiki kwenye kifaa chako.\n\nIli kupata maelezo zaidi, wasiliana na msimamizi wako."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Uliruhusu programu iweke muunganisho wa VPN.\n\nProgramu hii inaweza kufuatilia shughuli za kifaa na mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. \n\nMsimamizi wako ana uwezo wa kufuatilia shughuli ya mtandao wako ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\nKwa maelezo zaidi, wasiliana na msimamizi wako.\n\nUmeunganishwa pia kwenye VPN, ambayo inaweza kufuatilia shughuli za mtandao wako."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu, na tovuti. \n\nKwa maelezo zaidi, wasiliana na msimamizi wako."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu huu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia mtandao wako wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti. \n\n Wewe pia umeunganishwa kwenye <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako kibinafsi."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Kifaa kitaendelea kuwa katika hali ya kufungwa hadi utakapokifungua mwenyewe"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Pata arifa kwa haraka"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Panua"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Kunja"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrini imebandikwa"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Muhtasari ili ubandue."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Nimeelewa"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hapana, asante"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Imewashwa"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Imezimwa"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ukiwa na udhibiti wa arifa, unaweza kuweka kiwango cha umuhimu wa arifa za programu kuanzia 0 hadi 5. \n\n"<b>"Kiwango cha 5"</b>" \n- Onyesha katika sehemu ya juu ya orodha ya arifa \n- Ruhusu ukatizaji wa skrini nzima \n- Ruhusu arifa za kuchungulia kila wakati\n\n"<b>"Kiwango cha 4"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Ruhusu arifa za kuchungulia kila wakati \n\n"<b>"Kiwango cha 3"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia\n\n"<b>"Kiwango cha 2"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti au mtetemo \n\n"<b>"Kiwango cha 1"</b>" \n- Zuia ukatizaji wa skrini nzima \n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti na mtetemo \n- Usionyeshe skrini iliyofungwa na sehemu ya arifa \n- Onyesha katika sehemu ya chini ya orodha ya arifa \n\n"<b>"Kiwango cha 0"</b>" \n- Zuia arifa zote kutoka programu"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Arifa"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Hutapokea arifa hizi tena."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Arifa za <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Chini"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Wastani"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Juu"</string>
+    <string name="high_importance" msgid="730741630855788381">"Dharura"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Hakuna kukatizwa kwa sauti au maonyesho"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Onyesha chinichini"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Toa sauti"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Toa sauti na ibukizi kwenye skrini"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Vidhibiti vya arifa za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index de395b8..34daf43 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"பூட்டுத் திரை."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"அமைப்பு"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"மேலோட்டப் பார்வை."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"பணிப் பூட்டுத் திரை"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"மூடு"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"வைஃபை முடக்கப்பட்டது."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"பணிப் பயன்முறை"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"இரவு ஒளி"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"சமீபத்திய பணிகள் இல்லை"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"எல்லாவற்றையும் அழித்துவிட்டீர்கள்"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"பயன்பாட்டு தகவல்"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"சார்ஜ் செய்யப்பட்டது"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPNஐத் துண்டி"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"உங்கள் சாதனத்தை நிர்வகிப்பது: <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"உங்கள் சாதனத்தை நிர்வகிக்க, <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> பயன்பாட்டை <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> பயன்படுத்தும்."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"உங்கள் நிர்வாகியால் அமைப்புகள், நிறுவன அணுகல், பயன்பாடுகள், சாதனத்துடன் தொடர்புடைய தரவு, சாதன இருப்பிடத் தகவல் ஆகியவற்றைக் கண்காணிக்கவும் நிர்வகிக்கவும் முடியும்."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"மேலும் அறிக"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN அமைப்புகளைத் திற"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"உங்கள் நிர்வாகி நெட்வொர்க் பதிவெடுத்தலை இயக்கியுள்ளார், இது சாதனத்தில் ட்ராஃபிக்கைக் கண்காணிக்கும்.\n\nமேலும் தகவலுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN இணைப்பை அமைக்க, பயன்பாட்டிற்கு அனுமதி வழங்கியுள்ளீர்கள்.\n\nஇந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட, உங்கள் சாதனத்தையும் நெட்வொர்க் செயல்பாட்டையும் கண்காணிக்க முடியும்."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"உங்கள் பணி சுயவிவரத்தை நிர்வகிப்பது: <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nமின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டை நிர்வாகியால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்.\n\nஉங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய VPN இலும் இணைக்கப்பட்டுள்ளீர்கள்."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளீர்கள். இந்தப் பயன்பாட்டால் மின்னஞ்சல்கள், பயன்பாடுகள், இணையதளங்கள் உட்பட உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்க முடியும்."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION">%2$s</xliff:g> உடன் இணைக்கப்பட்டதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nகூடுதல் தகவலுக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"உங்கள் பணி சுயவிவரத்தை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், மின்னஞ்சல்கள், பயன்பாடுகள் மற்றும் இணையதளங்கள் உட்பட உங்கள் பணியிட நெட்வொர்க் செயல்பாட்டை அதனால் கண்காணிக்க முடியும்.\n\nமேலும் <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடன் இணைக்கப்பட்டுள்ளதால், உங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டையும் அதனால் கண்காணிக்க முடியும்."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"நீங்கள் கைமுறையாகத் திறக்கும் வரை, சாதனம் பூட்டப்பட்டிருக்கும்"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"விரைவாக அறிவிப்புகளைப் பெறுதல்"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"விரிவாக்கு"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"சுருக்கு"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"திரை பொருத்தப்பட்டது"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"புரிந்தது"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"வேண்டாம்"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"இயக்கத்தில்"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"முடக்கத்தில்"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ஆற்றல்மிக்க அறிவிப்புக் கட்டுப்பாடுகள் மூலம், பயன்பாட்டின் அறிவிப்புகளுக்கு முக்கியத்துவ நிலையை (0-5) அமைக்கலாம். \n\n"<b>"நிலை 5"</b>" \n- அறிவிப்புப் பட்டியலின் மேலே காட்டும் \n- முழுத் திரைக் குறுக்கீட்டை அனுமதிக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 4"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 3"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n\n"<b>"நிலை 2"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது, அதிர்வுறாது \n\n"<b>"நிலை 1"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது அல்லது அதிர்வுறாது \n- பூட்டுத்திரை மற்றும் நிலைப்பட்டியிலிருந்து மறைக்கும் \n- அறிவிப்புகள் பட்டியலின் கீழே காட்டும் \n\n"<b>"நிலை 0"</b>" \n- பயன்பாட்டின் எல்லா அறிவிப்புகளையும் தடுக்கும்"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"அறிவிப்புகள்"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"இந்த அறிவிப்புகளை இனி பெறமாட்டீர்கள்."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> அறிவிப்புகள்"</string>
+    <string name="min_importance" msgid="7559703098688382595">"குறைவான முக்கியத்துவம்"</string>
+    <string name="low_importance" msgid="6891335321576225228">"நடுத்தர முக்கியத்துவம்"</string>
+    <string name="default_importance" msgid="6400766013567512061">"அதிக முக்கியத்துவம்"</string>
+    <string name="high_importance" msgid="730741630855788381">"அவசரம்"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ஒலியெழுப்பாது அல்லது காட்சிக் குறுக்கீடு செய்யாது"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ஒலிக்காமல் காட்டும்"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ஒலியெழுப்பும்"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ஒலியெழுப்பி, திரையில் காட்டும்"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
     <string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> அறிவிப்புக் கட்டுப்பாடுகள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2254043..681bac2 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"లాక్ స్క్రీన్."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"సెట్టింగ్‌లు"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"అవలోకనం."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"కార్యాలయ లాక్ స్క్రీన్"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"మూసివేస్తుంది"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"వైఫై ఆఫ్ చేయబడింది."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"పని మోడ్"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"రాత్రి కాంతి"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"మీరు అన్నింటినీ తీసివేసారు"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"అనువర్తన సమాచారం"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ఛార్జ్ చేయబడింది"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPNను డిస్‌కనెక్ట్ చేయి"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"మీ పరికరం <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ద్వారా నిర్వహించబడుతోంది."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> మీ పరికరాన్ని నిర్వహించడానికి <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ని ఉపయోగిస్తుంది."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"మీ నిర్వాహకులు సెట్టింగ్‌లు, కార్పొరేట్ ప్రాప్యత, అనువర్తనాలు, మీ పరికరం అనుబంధిత డేటా మరియు స్థాన సమాచారం పర్యవేక్షించగలరు మరియు నిర్వహించగలరు."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"మరింత తెలుసుకోండి"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN సెట్టింగ్‌లను తెరవండి"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"మీ నిర్వాహకులు మీ పరికరంలో ట్రాఫిక్‌ను పర్యవేక్షించే నెట్‌వర్క్ లాగింగ్‌ను ఆన్ చేసారు.\n\nమరింత సమాచారం కోసం మీ నిర్వాహకులను సంప్రదించండి."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక అనువర్తనానికి అనుమతి ఇచ్చారు.\n\nఈ అనువర్తనం ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ పరికరం మరియు నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది.\n\nమీ నిర్వాహకుడు ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలరు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ చేయబడ్డారు, ఇది మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌‍సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకుడిని సంప్రదించండి."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"మీ కార్యాలయ ప్రొఫైల్‌ను <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహిస్తోంది. అలాగే, మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి కనెక్ట్ చేయబడింది, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు.\n\nమీరు <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా కనెక్ట్ చేయబడ్డారు, ఇది మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"మీరు మాన్యువల్‌గా అన్‌లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"నోటిఫికేషన్‌లను వేగంగా పొందండి"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"విస్తరింపజేయండి"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"కుదించండి"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"స్క్రీన్ పిన్ చేయబడింది"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి &amp; అలాగే పట్టుకోండి."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి స్థూలదృష్టిని తాకి &amp; అలాగే పట్టుకోండి."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"అర్థమైంది"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"వద్దు, ధన్యవాదాలు"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ఆన్‌లో ఉన్నాయి"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ఆఫ్‌లో ఉన్నాయి"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"పవర్ నోటిఫికేషన్ నియంత్రణలతో, మీరు అనువర్తన నోటిఫికేషన్‌ల కోసం ప్రాముఖ్యత స్థాయిని 0 నుండి 5 వరకు సెట్ చేయవచ్చు. \n\n"<b>"స్థాయి 5"</b>" \n- నోటిఫికేషన్ జాబితా పైభాగంలో చూపబడతాయి \n- పూర్తి స్క్రీన్ అంతరాయం అనుమతించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 4"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 3"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n\n"<b>"స్థాయి 2"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం మరియు వైబ్రేషన్ చేయవు \n\n"<b>"స్థాయి 1"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం లేదా వైబ్రేట్ చేయవు \n- లాక్ స్క్రీన్ మరియు స్థితి పట్టీ నుండి దాచబడతాయి \n- నోటిఫికేషన్ జాబితా దిగువ భాగంలో చూపబడతాయి \n\n"<b>"స్థాయి 0"</b>" \n- అనువర్తనం నుండి అన్ని నోటిఫికేషన్‌లు బ్లాక్ చేయబడతాయి"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"నోటిఫికేషన్‌లు"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"మీరు ఇకపై ఈ నోటిఫికేషన్‌లను పొందరు."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"దీని కోసం <xliff:g id="APP">%s</xliff:g> నోటిఫికేషన్‌లు"</string>
+    <string name="min_importance" msgid="7559703098688382595">"తక్కువ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"మధ్యస్థం"</string>
+    <string name="default_importance" msgid="6400766013567512061">"అధికం"</string>
+    <string name="high_importance" msgid="730741630855788381">"అత్యవసరం"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"శబ్ద లేదా దృశ్య అంతరాయం కలిగించవద్దు"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"నిశ్శబ్దంగా చూపు"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"శబ్దం చేయి"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"శబ్దం చేసి, స్క్రీన్‌పై చూపు"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్‌లు"</string>
     <string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> నోటిఫికేషన్ నియంత్రణలు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 258ccf6..230c258 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ล็อกหน้าจอ"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"การตั้งค่า"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ภาพรวม"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"หน้าจอล็อกของโปรไฟล์งาน"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ปิด"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ปิด Wi-Fi แล้ว"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"คำเตือน <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"โหมดการทำงาน"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"แสงตอนกลางคืน"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"ไม่มีรายการล่าสุด"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"คุณได้ล้างทุกอย่างแล้ว"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"แยกในแนวตั้ง"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"แยกแบบกำหนดเอง"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ชาร์จแล้ว"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"ยกเลิกการเชื่อมต่อ VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"อุปกรณ์ของคุณได้รับการจัดการโดย <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ใช้ <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> เพื่อจัดการอุปกรณ์"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"ผู้ดูแลระบบของคุณสามารถตรวจสอบและจัดการการตั้งค่า การเข้าถึงของบริษัท แอป และข้อมูลที่เชื่อมโยงกับอุปกรณ์ และข้อมูลตำแหน่งของอุปกรณ์ด้วย"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"เรียนรู้เพิ่มเติม"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"คุณเชื่อมต่อกับ <xliff:g id="VPN_APP">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"เปิดการตั้งค่า VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"ผู้ดูแลระบบของคุณเปิดการทำบันทึกเครือข่าย ซึ่งจะติดตามดูการรับส่งข้อมูลบนอุปกรณ์ \n\nหากต้องการข้อมูลเพิ่มเติม ให้ติดต่อผู้ดูแลระบบของคุณ"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"คุณได้ให้สิทธิ์แอปในการตั้งค่าการเชื่อมต่อ VPN\n\nแอปนี้จะสามารถตรวจสอบอุปกรณ์และกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g>\n\nผู้ดูแลระบบของคุณสามารถตรวจสอบกิจกรรมในเครือข่ายรวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ\n\nนอกจากนี้คุณยังมีการเชื่อมต่อ VPN ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"คุณเชื่อมต่อกับ <xliff:g id="APPLICATION">%1$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ รวมถึงอีเมล แอป และเว็บไซต์ได้"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nสำหรับข้อมูลเพิ่มเติม โปรดติดต่อผู้ดูแลระบบ"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"โปรไฟล์งานได้รับการจัดการโดย <xliff:g id="ORGANIZATION">%1$s</xliff:g> โดยมีการเชื่อมต่อกับ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่าย รวมถึงอีเมล แอป และเว็บไซต์ได้\n\nนอกจากนี้ คุณยังเชื่อมต่อกับ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวได้"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"อุปกรณ์จะล็อกจนกว่าคุณจะปลดล็อกด้วยตนเอง"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"รับการแจ้งเตือนเร็วขึ้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c156a8e..7bd443c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Mga Setting"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Lock screen sa trabaho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Isara"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Na-off ang wifi."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Babala sa <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Walang mga kamakailang item"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Na-clear mo ang lahat"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Custom"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Nasingil na"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Idiskonekta ang VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Pinamamahalaan ng <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ang iyong device."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Ginagamit ng <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ang <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> upang pamahalaan ang iyong device."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Masusubaybayan at mapapamahalaan ng admin mo ang mga setting, pangkorporasyong access, app, data sa device at impormasyon ng lokasyon ng device mo."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Matuto pa"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Kumonekta ka sa <xliff:g id="VPN_APP">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kasama ang mga email, app at website."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Buksan ang Mga Setting ng VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Na-on ng iyong admin ang pag-log sa network, na sumusubaybay sa trapiko sa device mo.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong admin."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Nagbigay ka ng pahintulot sa app upang mag-set up ng VPN na koneksyon.\n\nMaaaring subaybayan ng app na ito ang iyong aktibidad sa device at network, kabilang ang mga email, app at website."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Pinapamahalaan ang iyong profile ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nMay kakayahan ang iyong administrator sa pagsubaybay ng iyong aktibidad sa network kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator.\n\nNakakonekta ka rin sa isang VPN, na maaaring sumubaybay sa iyong aktibidad sa network."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network kabilang ang mga email, app at website."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network, kabilang ang mga email, app at website."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Nakakonekta ka sa <xliff:g id="APPLICATION">%1$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network, kabilang ang mga email, app at website."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nPara sa higit pang impormasyon, makipag-ugnayan sa iyong administrator."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Ang iyong profile sa trabaho ay pinapamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Nakakonekta ito sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa iyong aktibidad sa network, kabilang ang mga email, app at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa iyong personal na aktibidad sa network."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Mananatiling naka-lock ang device hanggang sa manu-mano mong i-unlock"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Kunin ang notification nang mas mabilis"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e5dddbe..f6b42c9 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Kilit ekranı"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ayarlar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Genel Bakış."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"İş profili kilit ekranı"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Kapat"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Kablosuz kapatıldı."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Çalışma modu"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gece Işığı"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Yeni öğe yok"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Her şeyi sildiniz"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN bağlantısını kes"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Cihazınız <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> tarafından yönetiliyor."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, cihazınızı yönetmek için <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> kullanıyor."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Yöneticiniz ayarları, kurumsal erişimi, uygulamaları, cihazınızla ilişkilendirilen verileri ve cihazınızın konum bilgilerini takip edip yönetebilir."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Daha fazla bilgi"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"E-postalarınız, uygulamalarınız ve web siteleriniz de dahil olmak üzere ağ etkinliğinizi takip edebilen <xliff:g id="VPN_APP">%1$s</xliff:g> ağına bağlısınız."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN Ayarlarını aç"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Yöneticiniz,cihazınızdaki trafiği izleyen ağ günlük kaydını açtı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"VPN bağlantısı kurması için bir uygulamaya izin verdiniz.\n\nBu uygulama, cihazınızın yanı sıra e-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilir."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Cihazınız <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor.\n\nYöneticiniz; e-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilir.\n\nDaha fazla bilgi edinmek için yöneticinizle iletişim kurun.\n\nAyrıca ağ etkinliğinizi izleyebilen bir VPN\'ye bağlısınız."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlı.\n\nDaha fazla bilgi için yöneticinizle iletişim kurun."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\n Ayrıca kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Cihazınızın kilidini manuel olarak açmadıkça cihaz kilitli kalacak"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirimleri daha hızlı alın"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişlet"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Daralt"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran sabitlendi"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Genel bakış\'a dokunup basılı tutun."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hayır, teşekkürler"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Açık"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kapalı"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Güç bildirim kontrolleriyle, bir uygulamanın bildirimleri için 0 ile 5 arasında bir önem düzeyi ayarlayabilirsiniz. \n\n"<b>"5. Düzey"</b>" \n- Bildirim listesinin en üstünde gösterilsin \n- Tam ekran kesintisine izin verilsin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"4. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"3. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n\n"<b>"2. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman belirmesin \n- Hiçbir zaman ses çıkarmasın ve titreştirmesin \n\n"<b>"1. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n- Hiçbir zaman ses çıkarmasın veya titreştirmesin \n- Kilit ekranından ve durum çubuğundan gizlensin \n- Bildirim listesinin en altında gösterilsin \n\n"<b>"0. Düzey"</b>" \n- Uygulamadan gelen tüm bildirimler engellensin"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirimler"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Bu bildirimleri artık almayacaksınız."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Şunun için <xliff:g id="APP">%s</xliff:g> bildirimleri:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Düşük"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Orta"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Yüksek"</string>
+    <string name="high_importance" msgid="730741630855788381">"Acil"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ses veya görsel kesme yok"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Sessiz bir şekilde göster"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ses çıkar"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ses çıkar ve ekranda göster"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirim denetimleri"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 50887c6..5d58046 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заблокований екран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Налаштування"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Огляд."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Екран блокування завдання"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрити"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi вимкнено."</string>
@@ -328,6 +327,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Робочий режим"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нічний режим"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Немає нещодавніх завдань"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ви очистили все"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
@@ -341,6 +346,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
@@ -421,20 +436,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Від’єднатися від мережі VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Вашим пристроєм керує додаток <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"Компанія <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> керує вашим пристроєм за допомогою додатка <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Адміністратор може відстежувати й контролювати налаштування, корпоративний доступ, додатки, дані на пристрої та дані про місцезнаходження пристрою."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Докладніше"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Під’єднано додаток <xliff:g id="VPN_APP">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, як-от доступ до електронної пошти, додатків і веб-сайтів."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Відкрити налаштування мережі VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Ваш адміністратор увімкнув реєстрацію в мережі, під час якої на вашому пристрої відстежується трафік.\n\nЩоб дізнатися більше, зв’яжіться зі своїм адміністратором."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Ви дозволили додатку під’єднуватися до мережі VPN.\n\nЦей додаток може відстежувати вашу активність на пристрої та в мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Вашим пристроєм керує організація <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nАдміністратор може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше.\n\nПристрій під’єднано до мережі VPN, у якій ваша активність може відстежуватись."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ваш профіль під’єднано до додатка <xliff:g id="APPLICATION">%1$s</xliff:g>, який може відстежувати вашу особисту активність у мережі, зокрема доступ до електронної пошти, додатків і веб-сайтів."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nЗв’яжіться з адміністратором, щоб дізнатися більше."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Вашим робочим профілем керує <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Профіль під’єднано до додатка <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, який може відстежувати вашу робочу активність у мережі, зокрема в електронній пошті, додатках і на веб-сайтах.\n\nВаш профіль також під’єднано до додатка <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, який може відстежувати вашу особисту активність у мережі."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Пристрій залишатиметься заблокованим, доки ви не розблокуєте його вручну"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Швидше отримуйте сповіщення"</string>
@@ -446,10 +465,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Розгорнути"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згорнути"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран закріплено"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопку \"Огляд\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Зрозуміло"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ні, дякую"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +533,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Увімк."</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Вимк."</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"За допомогою елементів керування сповіщеннями ви можете налаштувати пріоритет сповіщень додатка – від 0 до 5 рівня. \n\n"<b>"Рівень 5"</b>\n"- Показувати сповіщення вгорі списку \n- Виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 4"</b>\n"- Не виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 3"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n\n"<b>"Рівень 2"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n\n"<b>"Рівень 1"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n- Не показувати на заблокованому екрані та в рядку стану \n- Показувати сповіщення внизу списку \n\n"<b>"Рівень 0"</b>\n"- Блокувати всі сповіщення з додатка"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Сповіщення"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ви більше не отримуватимете ці сповіщення."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Сповіщення з додатка <xliff:g id="APP">%s</xliff:g>:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Низький"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Середній"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Високий"</string>
+    <string name="high_importance" msgid="730741630855788381">"Терміново"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звуку та візуальних сповіщень"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Показувати без звукового сигналу"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Зі звуком"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Зі звуком і спливаючими вікнами"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Елементи керування сповіщеннями додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f9ca3b2..53c67e7 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"مقفل اسکرین۔"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ترتیبات"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"مجموعی جائزہ۔"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"دفتری مقفل اسکرین"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"بند کریں"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>۔"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏Wifi کو آف کر دیا گیا۔"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"کام موڈ"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"نائٹ لائٹ"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"کوئی حالیہ آئٹم نہیں"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"آپ نے سب کچھ صاف کر دیا ہے"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ایپلیکیشن کی معلومات"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"چارج ہوگئی"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"‏VPN کو غیر منسلک کریں"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"آپ کا آلہ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> کے زیر انتظام ہے۔"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> آپ کے آلہ کے نظم کیلئے <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> استعمال کرتا ہے۔"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"آپ کا منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کو مانیٹر اور ان کا نظم کر سکتا ہے۔"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"مزید جانیں"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"آپ <xliff:g id="VPN_APP">%1$s</xliff:g> سے منسلک ہیں جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"‏VPN کی ترتیبات کھولیں"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"آپ کے ایڈمن نے نیٹ ورک لاگنگ آن کر دی ہے، جو آپ کے آلہ پر ٹریفک کو مانیٹر کرتی ہے۔\n\nمزید معلومات کیلئے اپنے ایڈمن سے رابطہ کریں۔"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"‏آپ نے ایک ایپ کو VPN کنکشن ترتیب دینے کی اجازت دی ہے۔\n\nیہ ایپ ای میلز، ایپس اور ویب سائٹس سمیت آپ کے آلہ اور نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"‏آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔\n\nآپ کا منتظم ای میلز، ایپس اور ویب سائٹس سیمت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتا ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔\n\nآپ ایک VPN سے بھی منسلک ہیں، جو آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتا ہے۔"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نجی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ یہ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی کو مانیٹر کر سکتی ہے۔"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"آلہ اس وقت تک مقفل رہے گا جب تک آپ دستی طور پر اسے غیر مقفل نہ کریں"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"تیزی سے اطلاعات حاصل کریں"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"پھیلائیں"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"سکیڑیں"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"اسکرین پن کردہ ہے"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"سمجھ آ گئی"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"نہیں شکریہ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"آن"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"آف"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"پاور اطلاع کنٹرولز کے ساتھ آپ کسی ایپ کی اطلاعات کیلئے 0 سے 5 تک اہمیت کی سطح سیٹ کر سکتے ہیں۔ \n\n"<b>"سطح 5"</b>\n"- اطلاعات کی فہرست کے اوپر دکھائیں \n- پوری اسکرین کی مداخلت کی اجازت دیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 4"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 3"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n\n"<b>"سطح 2"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n- کبھی آواز اور ارتعاش پیدا نہ کرنا \n\n"<b>" سطح 1"</b>\n"- پوری اسکرین کی مداخلت کو روکنا \n- کبھی نہ جھانکنا \n- کبھی بھی آواز یا ارتعاش پیدا نہ کرنا\n- مقفل اسکرین اور اسٹیٹس بار سے چھپانا \n - اطلاع کی فہرست کی نیچے دکھانا \n\n"<b>"سطح 0"</b>\n"- ایپ سے تمام اطلاعات مسدود کریں"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"اطلاعات"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"آپ کو یہ اطلاعات مزید نہیں ملیں گی۔"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> کیلئے اطلاعات"</string>
+    <string name="min_importance" msgid="7559703098688382595">"کم"</string>
+    <string name="low_importance" msgid="6891335321576225228">"متوسط"</string>
+    <string name="default_importance" msgid="6400766013567512061">"زیادہ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ارجنٹ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"آواز یا بصری مداخلت نہیں ہے"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"خاموشی سے دکھائیں"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"آواز نکالیں"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"آواز نکالیں اور اسکرین پر پاپ کریں"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
     <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے نوٹیفکیشن کنٹرولز"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 413cd7a3..9ea82d6 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Qulflash ekrani."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Sozlamalar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Umumiy nazar."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ishchi ekran qulfi"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Yopish"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi o‘chirildi."</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ish rejimi"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Tungi rejim"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Hozircha hech narsa yo‘q"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hammasi o‘chirildi"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Batareya quvvati to‘ldi"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ulanishini uzish"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Qurilmangiz <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> tomonidan boshqariladi."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> qurilmangizni boshqarish uchun <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ilovasidan foydalanadi."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Administratoringiz qurilmangiz bilan bog‘liq sozlamalar, korporativ kirish huquqi, ilova va ma’lumotlarni hamda qurilmangizning joylashuv axborotini kuzatishi va boshqarishi mumkin."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Batafsil"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"<xliff:g id="VPN_APP">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"VPN sozlamalarini ochish"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Administrator qurilmangizdagi trafikni nazorat qiluvchi tarmoq jurnalini yoqdi.\n\nBatafsil ma’lumot olish uchun administratoringizga murojaat qiling."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Siz ilovaga VPN tarmog‘iga ulanishga ruxsat bergansiz.\n\nUshbu ilova qurilmangiz va internetdagi harakatlaringizni, jumladan, e-pochta, ilovalar va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi.\n\nAdministrator internetdagi harakatlaringizni, jumladan, e-pochta, ilova va xavfsiz veb-saytlar bilan ishlashingizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning.\n\nShuningdek, siz VPN tarmog‘iga ham ulangansiz. U internetdagi harakatlaringizni kuzatishi mumkin."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nBatafsil ma’lumot olish uchun administrator bilan bog‘laning."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Sizning ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi harakatlaringizni, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Qurilma qo‘lda qulfdan chiqarilmaguncha qulflangan holatda qoladi"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirishnomalarni tezroq oling"</string>
@@ -442,10 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Yoyish"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yig‘ish"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran qadaldi"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Umumiy ma’lumot” tugmasini bosib turing."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yo‘q, kerakmas"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Yoniq"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"O‘chiq"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Bildirishnomalar uchun kengaytirilgan boshqaruv yordamida ilova bildirishnomalarining muhimlik darajasini (0-5) sozlash mumkin. \n\n"<b>"5-daraja"</b>" \n- Bildirishnomani ro‘yxatning boshida ko‘rsatish \n- To‘liq ekranli bildirishnomalarni ko‘rsatish \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"4-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"3-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n\n"<b>"2-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n\n"<b>"1-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n- Ekran qulfi va holat qatorida ko‘rsatmaslik \n- Bildirishnomani ro‘yxatning oxirida ko‘rsatish \n\n"<b>"0-daraja"</b>" \n- Ilovadan keladigan barcha bildirishnomalarni bloklash"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirishnomalar"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ushbu bildirishnomalar endi ko‘rsatilmaydi."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> bildirishnomalari"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Muhim emas"</string>
+    <string name="low_importance" msgid="6891335321576225228">"O‘rtacha"</string>
+    <string name="default_importance" msgid="6400766013567512061">"O‘ta muhim"</string>
+    <string name="high_importance" msgid="730741630855788381">"Shoshilinch"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bildirishnomalarsiz"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Ovozsiz"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ovozli"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ovoz va qalqib chiquvchi oyna"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalarini boshqarish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dde279b..6817871 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Màn hình khóa."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Cài đặt"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Tổng quan."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Màn hình khóa công việc"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Đóng"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Đã tắt Wifi."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Chế độ làm việc"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Đèn đọc sách"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Không có mục gần đây nào"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Bạn đã xóa mọi nội dung"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Phân tách dọc"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tùy chỉnh phân tách"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Đã sạc đầy"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Ngắt kết nối VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Thiết bị của bạn do <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> quản lý."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> sử dụng <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> để quản lý thiết bị của bạn."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Quản trị viên có thể giám sát &amp; q.lý cài đặt, quyền truy cập d.liệu công ty, ứng dụng, d.liệu được liên kết với thiết bị &amp; thông tin vị trí thiết bị của bạn."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Tìm hiểu thêm"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Bạn đang kết nối với <xliff:g id="VPN_APP">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Mở cài đặt VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Quản trị viên đã bật tính năng ghi nhật ký mạng. Tính năng này giám sát lưu lượng truy cập trên thiết bị của bạn.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Bạn đã cấp cho ứng dụng quyền thiết lập kết nối VPN.\n\nỨng dụng này có thể giám sát hoạt động mạng và thiết bị của bạn, bao gồm email, ứng dụng và trang web."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Hồ sơ Android Work của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nQuản trị viên có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn.\n\nBạn cũng được kết nối với VPN, có thể giám sát hoạt động mạng của bạn."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng của bạn bao gồm email, ứng dụng và trang web."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Bạn đang kết nối với <xliff:g id="APPLICATION">%1$s</xliff:g>. Ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn bao gồm email, ứng dụng và trang web."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nĐể biết thêm thông tin, hãy liên hệ với quản trị viên của bạn."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Hồ sơ công việc của bạn được quản lý bởi <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Hồ sơ được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cơ quan của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng được kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, có thể giám sát hoạt động mạng cá nhân của bạn."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Thiết bị sẽ vẫn bị khóa cho tới khi bạn mở khóa theo cách thủ công"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Nhận thông báo nhanh hơn"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mở rộng"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Thu gọn"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Màn hình được ghim"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ok"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Không, cảm ơn"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +529,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Bật"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Tắt"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Với các kiểm soát thông báo nguồn, bạn có thể đặt cấp độ quan trọng từ 0 đến 5 cho các thông báo của ứng dụng. \n\n"<b>"Cấp 5"</b>" \n- Hiển thị ở đầu danh sách thông báo \n- Cho phép gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 4"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 3"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n\n"<b>"Cấp 2"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n\n"<b>"Cấp 1"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n- Ẩn khỏi màn hình khóa và thanh trạng thái \n- Hiển thị ở cuối danh sách thông báo \n\n"<b>"Cấp 0"</b>" \n- Chặn tất cả các thông báo từ ứng dụng"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Thông báo"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Bạn sẽ không nhận được những thông báo này nữa."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Thông báo của <xliff:g id="APP">%s</xliff:g> cho"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Thấp"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Trung bình"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Cao"</string>
+    <string name="high_importance" msgid="730741630855788381">"Khẩn cấp"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Không làm gián đoạn bằng âm báo hoặc hình ảnh"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Hiển thị mà không phát âm báo"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Phát âm báo"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Phát âm báo và hiển thị trên màn hình"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
     <string name="notification_done" msgid="5279426047273930175">"Xong"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Điều khiển thông báo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4f5518b..f22fc3d 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"锁定屏幕。"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"设置"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"概览。"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"工作锁定屏幕"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"关闭"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WLAN已关闭。"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜间模式"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"近期没有任何内容"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有内容"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自定义分割"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充满"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"断开VPN连接"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"您的设备由<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>管理。"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>会使用<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>管理您的设备。"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"您的管理员能够监控和管理与您的设备相关的设置、企业权限、应用、数据以及您设备的位置信息。"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"了解详情"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"您已连接到<xliff:g id="VPN_APP">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"打开 VPN 设置"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"您的管理员已开启网络日志功能,该功能会监控您设备上的流量。\n\n要了解详情,请与您的管理员联系。"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"您已授权应用设置 VPN 连接。\n\n该应用可以监控您的设备和网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您单位的管理员可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。\n\n此外,您还连接到了 VPN,此 VPN 也可以监控您的网络活动。"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n若要了解详情,请与您单位的管理员联系。"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作资料由以下单位管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。您已连接到<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,该应用可以监控您的工作网络活动,包括收发电子邮件、使用应用和浏览网站。\n\n此外,您还连接到了<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,该应用可以监控您的个人网络活动。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"在您手动解锁之前,设备会保持锁定状态"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"更快捷地查看通知"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 947848e..9e74d41 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"上鎖畫面。"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"設定"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"概覽"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"工作螢幕鎖定"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"關閉"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi 已關閉。"</string>
@@ -324,6 +323,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈模式"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"沒有最近項目"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有項目"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
@@ -337,6 +342,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已完成充電"</string>
@@ -417,20 +432,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"中斷 VPN 連線"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"您的裝置由「<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>」管理。"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>使用「<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>」管理您的裝置。"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"您的管理員可以監控及管理您裝置的設定、企業存取、應用程式、資料及位置資訊。"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"瞭解詳情"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"您已連接至「<xliff:g id="VPN_APP">%1$s</xliff:g>」,此應用程式可以監控您的網絡活動,包括電郵、應用程式及網站。"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"開啟 VPN 設定"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"您的管理員已開啟網絡記錄功能,以監控您裝置上的流量。\n\n如需瞭解詳情,請聯絡您的管理員。"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"您已授權應用程式設定 VPN 連線。\n\n這個應用程式能夠監控您的裝置和網絡活動,包括電郵、應用程式和網站。"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"您的裝置由 <xliff:g id="ORGANIZATION">%1$s</xliff:g> 管理。\n\n您的管理員可以監控您的網絡活動,包括電郵、應用程式及網站。\n\n如需瞭解更多資訊,請聯絡管理員。\n\n由於您的裝置連至 VPN,因此 VPN 服務供應商也可監控您的網絡活動。"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g> ,它能夠監控您的網絡活動,包括電郵、應用程式和網站。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"您已連結至<xliff:g id="APPLICATION">%1$s</xliff:g>,它能夠監控您的個人網絡活動,包括電郵、應用程式和網站。"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已連接至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的個人網絡活動,包括電郵、應用程式及網站。"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n如需進一步資訊,請聯絡您的管理員。"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。它已連結至<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,能夠監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n此外,您亦連結至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,因此它亦能夠監控您的個人網絡活動。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"裝置將保持上鎖,直到您手動解鎖"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
@@ -442,8 +461,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string>
-    <string name="screen_pinning_description" msgid="8909878447196419623">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
-    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
+    <string name="screen_pinning_description" msgid="8909878447196419623">"畫面將會繼續顯示,直至您取消固定。按住 [返回] 和 [概覽] 即可取消固定。"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"畫面將會繼續顯示,直至您取消固定。按住 [概覽] 即可取消固定。"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"不用了,謝謝"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -511,7 +530,7 @@
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"關閉"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"通知控制項讓您設定應用程式通知的重要性 (0 至 5 級)。\n\n"<b>"第 5 級"</b>" \n- 在通知清單頂部顯示 \n- 允許全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 4 級"</b>" \n- 阻止全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 3 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n\n"<b>"第 2 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n\n"<b>"第 1 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n- 從上鎖畫面和狀態列中隱藏 \n- 在通知清單底部顯示 \n\n"<b>"第 0 級"</b>" \n- 封鎖所有應用程式通知"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
-    <string name="notification_channel_disabled" msgid="5805874247999578073">"你不會再收到這類通知。"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"您不會再收到這些通知。"</string>
     <string name="notification_importance_header_app" msgid="3572576545406258751">"以下頻道的「<xliff:g id="APP">%s</xliff:g>」通知:"</string>
     <string name="min_importance" msgid="7559703098688382595">"低"</string>
     <string name="low_importance" msgid="6891335321576225228">"中"</string>
@@ -520,7 +539,7 @@
     <string name="notification_importance_min" msgid="3237794091374404537">"不發出音效或顯示通知"</string>
     <string name="notification_importance_low" msgid="8929105501798019743">"顯示通知但不發出音效"</string>
     <string name="notification_importance_default" msgid="9025125660733917469">"發出音效"</string>
-    <string name="notification_importance_high" msgid="3316555356062640222">"發出音效並在畫面上彈出通知"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"發出音效並在螢幕上彈出通知"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b0aa942..1d52de3 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"螢幕鎖定。"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"設定"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"總覽。"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work 螢幕鎖定"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"關閉"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi 已關閉。"</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"最近沒有任何項目"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有工作"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"已充飽"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"中斷 VPN 連線"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"你的裝置是由「<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>」所管理。"</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> 使用「<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>」管理你的裝置。"</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"你的管理員可以監控及管理與你的裝置相關聯的設定、公司系統權限、應用程式和資料,以及裝置的位置資訊。"</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"瞭解詳情"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"由於你已連結至「<xliff:g id="VPN_APP">%1$s</xliff:g>」,你的網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"開啟 VPN 設定"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"你的管理員已啟用網路紀錄功能,可監控你裝置上的流量。\n\n如需詳細資訊,請與你的管理員聯絡。"</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"您已授權一個應用程式設定 VPN 連線。\n\n這個應用程式可以監控您的裝置和網路活動,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"您的 Work 設定檔由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。\n\n您的管理員可以監控您的網路活動,包括收發電子郵件、使用應用程式及瀏覽網站。\n\n如需詳細資訊,請洽您的管理員。\n\n同時,由於您的裝置已連線至 VPN,您的網路活動也會受到 VPN 監控。"</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"由於您已連線至 <xliff:g id="APPLICATION">%1$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。"</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,你的個人網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n詳情請洽您的管理員。"</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"您的 Work 設定檔是由下列機構管理:<xliff:g id="ORGANIZATION">%1$s</xliff:g>。由於設定檔已連線至 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>,您的工作網路活動也會受到這個應用程式監控,包括收發電子郵件、使用應用程式和瀏覽網站。\n\n同時由於您也連線至<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>,您的個人網路活動也會受到這個應用程式監控。"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"在您手動解鎖前,裝置將保持鎖定狀態"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d5f98c2..0723e7e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Khiya isikrini."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Izilungiselelo"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Buka konke."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ukukhiya isikrini somsebenzi"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Vala"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"I-Wifi ivaliwe."</string>
@@ -322,6 +321,12 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Imodi yomsebenzi"</string>
     <string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ukukhanya kwasebusuku"</string>
+    <!-- no translation found for quick_settings_nfc_label (9012153754816969325) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_off (6883274004315134333) -->
+    <skip />
+    <!-- no translation found for quick_settings_nfc_on (6680317193676884311) -->
+    <skip />
     <string name="recents_empty_message" msgid="808480104164008572">"Azikho izinto zakamuva"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Usule yonke into"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
@@ -335,6 +340,16 @@
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</string>
+    <!-- no translation found for recents_accessibility_dismissed (2354459747918667050) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_open (1651449827614876864) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_top (9056056469282256287) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_left (8987144699630620019) -->
+    <skip />
+    <!-- no translation found for recents_accessibility_split_screen_right (275069779299592867) -->
+    <skip />
   <string-array name="recents_blacklist_array">
   </string-array>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kushajiwe"</string>
@@ -415,20 +430,24 @@
     <string name="disconnect_vpn" msgid="1324915059568548655">"Nqamula i-VPN"</string>
     <string name="monitoring_description_do_header_generic" msgid="96588491028288691">"Idivayisi yakho iphethwe yi-<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_description_do_header_with_name" msgid="5511133708978206460">"I-<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> isebenzisa i-<xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> ukuze iphathe idivayisi yakho."</string>
-    <string name="monitoring_description_do_body" msgid="6764108354701060766">"Umlawuli wakho angaqaphela aphinde aphathe izilungiselelo, ukufinyelela kwezinkampani, izinhlelo zokusebenza, idatha ehlotshaniswa nedivayisi yakho, nolwazi lwendawo yedivayisi yakho."</string>
+    <!-- no translation found for monitoring_description_do_body (3639594537660975895) -->
+    <skip />
     <string name="monitoring_description_do_learn_more_separator" msgid="3785251953067436862">" "</string>
     <string name="monitoring_description_do_learn_more" msgid="1849514470437907421">"Funda kabanzi"</string>
     <string name="monitoring_description_do_body_vpn" msgid="8255218762488901796">"Uxhumeke ku-<xliff:g id="VPN_APP">%1$s</xliff:g>, engaqapha umsebenzi wenethiwekhi yakho, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="1933186756733474388">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="8869300202410505143">"Vula izilungiselelo ze-VPN"</string>
-    <string name="monitoring_description_network_logging" msgid="3901006351911787915">"Umlawuli wakho uvule ukungena kwenethiwekhi, okuhlola ithrafikhi kudivayisi yakho.\n\nNgolwazi olubanzi xhumana nomlawuli wakho."</string>
+    <!-- no translation found for monitoring_description_network_logging (7223505523384076027) -->
+    <skip />
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Unikeze uhlelo lokusebenza imvume yokusetha ukuxhumana kwe-VPN.\n\nLolu hlelo lokusebenza lungahlola idivayisi yakho nomsebenzi wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUmqondisi wakho unamandla wokuqaphela umsebenzi wenethiwekhi yakho ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho.\n\nFuthi uxhumeke ku-VPN, engaqaphela umsebenzi wenethiwekhi yakho."</string>
+    <!-- no translation found for monitoring_description_vpn_profile_owned (2958019119161161530) -->
+    <skip />
     <string name="legacy_vpn_name" msgid="6604123105765737830">"I-VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wakho wenethiwekhi ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Uxhumeke ku-<xliff:g id="APPLICATION">%1$s</xliff:g>, engaqapha umsebenzi wakho womuntu siqu wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yokusebenza, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nUkuze uthole olunye ulwazi, xhumana nomqondisi wakho."</string>
+    <!-- no translation found for monitoring_description_app_work (7777228449969022305) -->
+    <skip />
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Iphrofayela yakho yomsebenzi iphethwe yi-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomsebenzi, ofaka ama-imeyili, izinhlelo zokusebenza namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engahlola umsebenzi wenethiwekhi yakho yomuntu siqu."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Idivayisi izohlala ikhiyekile uze uyivule ngokwenza"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Thola izaziso ngokushesha"</string>
@@ -440,10 +459,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Nweba"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Goqa"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Isikrini siphiniwe"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe okuthi Emuva Nokubuka konke ukuze ususe ukuphina."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe Ukubuka konke ukuze ususe ukuphina."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ngiyitholile"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Cha ngiyabonga"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +527,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Vuliwe"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Valiwe"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ngezilawuli zesaziso zamandla, ungasetha ileveli ebalulekile kusuka ku-0 kuya ku-5 kusuka kuzaziso zohlelo lokusebenza. \n\n"<b>"Ileveli 5"</b>" \n- Ibonisa phezulu kuhlu lwesaziso \n- Vumela ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 4"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 3"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n\n"<b>"Ileveli 2"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo nokudlidliza \n\n"<b>"Ileveli 1"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo noma ukudlidliza \n- Fihla kusuka kusikrini sokukhiya nebha yesimo \n- Bonisa phansi kohlu lwesaziso \n\n"<b>"Ileveli 0"</b>" \n- Vimbela zonke izaziso kusuka kuhlelo lokusebenza"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Izaziso"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ngeke usathola lezi zaziso."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> izaziso ze-"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Phansi"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Okulingene"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Okuphezulu"</string>
+    <string name="high_importance" msgid="730741630855788381">"Okuphuthumayo"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Awukho umsindo noma ukuphazamiseka okubukwayo"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Bonisa ngokuthulile"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Yenza umsindo"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Yenza umsindo ne-pop kusikrini"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> izilawuli zasaziso"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index a229866..7fb513c 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -40,8 +40,9 @@
         <attr name="decayTime" format="integer" />
         <attr name="orientation" />
     </declare-styleable>
+    <attr name="frameColor" format="color" />
     <declare-styleable name="BatteryMeterView">
-        <attr name="frameColor" format="color" />
+        <attr name="frameColor" />
     </declare-styleable>
     <declare-styleable name="Clock">
         <attr name="amPmStyle" format="enum">
@@ -60,7 +61,7 @@
         <attr name="framePadding" format="dimension" />
         <!-- {@deprecated Use a statelist in frameColor instead.} -->
         <attr name="activeFrameColor" format="color" />
-        <attr name="frameColor" format="color" />
+        <attr name="frameColor" />
         <attr name="badgeDiameter" format="dimension" />
         <attr name="badgeMargin" format="dimension" />
     </declare-styleable>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 50ef392..ac86439 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -297,4 +297,11 @@
          If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
     <integer name="config_warningTemperature">-1</integer>
 
+    <!-- Accessibility actions -->
+    <item type="id" name="action_split_task_to_left" />
+    <item type="id" name="action_split_task_to_right" />
+    <item type="id" name="action_split_task_to_top" />
+    <item type="id" name="action_open" />
+    <item type="id" name="action_dimiss" />
+
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 78d211f..79529a7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -75,6 +75,9 @@
     <!-- Height of a large notification in the status bar -->
     <dimen name="notification_max_height">284dp</dimen>
 
+    <!-- Height of an ambient notification on ambient display -->
+    <dimen name="notification_ambient_height">400dp</dimen>
+
     <!-- Height of a heads up notification in the status bar for legacy custom views -->
     <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
 
@@ -161,7 +164,7 @@
     <dimen name="close_handle_underlap">32dp</dimen>
 
     <!-- Height of the status bar header bar -->
-    <dimen name="status_bar_header_height">104dp</dimen>
+    <dimen name="status_bar_header_height">126dp</dimen>
 
     <!-- Height of the status bar header bar when expanded -->
     <dimen name="status_bar_header_height_expanded">116dp</dimen>
@@ -201,8 +204,8 @@
     <!-- The size of the gesture span needed to activate the "pull" notification expansion -->
     <dimen name="pull_span_min">25dp</dimen>
 
-    <dimen name="qs_tile_height">88dp</dimen>
-    <dimen name="qs_tile_margin">16dp</dimen>
+    <dimen name="qs_tile_height">80dp</dimen>
+    <dimen name="qs_tile_margin">36dp</dimen>
     <dimen name="qs_tile_margin_top">16dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
@@ -418,7 +421,7 @@
     <dimen name="qs_time_collapsed_size">14sp</dimen>
 
     <!-- The font size of the time when expanded in QS -->
-    <dimen name="qs_time_expanded_size">20sp</dimen>
+    <dimen name="qs_time_expanded_size">14sp</dimen>
 
     <!-- The font size of the "emergency calls only" label in QS -->
     <dimen name="qs_emergency_calls_only_text_size">12sp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml
index 94ffdb1..5858443 100644
--- a/packages/SystemUI/res/values/dimens_grid.xml
+++ b/packages/SystemUI/res/values/dimens_grid.xml
@@ -21,5 +21,7 @@
   <dimen name="recents_grid_padding_task_view">20dp</dimen>
   <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>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 69515fa..422431e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -760,6 +760,12 @@
     <string name="quick_settings_work_mode_label">Work mode</string>
     <!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
     <string name="quick_settings_night_display_label">Night Light</string>
+    <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_nfc_label">NFC</string>
+    <!-- QuickSettings: NFC (off) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_nfc_off">NFC is disabled</string>
+    <!-- QuickSettings: NFC (on) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_nfc_on">NFC is enabled</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">No recent items</string>
@@ -788,6 +794,16 @@
     <string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
     <!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
     <string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
+    <!-- Recents: Accessibility dismiss label -->
+    <string name="recents_accessibility_dismissed">Dismiss</string>
+    <!-- Recents: Accessibility open label -->
+    <string name="recents_accessibility_open">Open</string>
+    <!-- Recents: Accessibility split to the top -->
+    <string name="recents_accessibility_split_screen_top">Split screen to the top</string>
+    <!-- Recents: Accessibility split to the left -->
+    <string name="recents_accessibility_split_screen_left">Split screen to the left</string>
+    <!-- Recents: Accessibility split to the right -->
+    <string name="recents_accessibility_split_screen_right">Split screen to the right</string>
 
     <!-- Fully qualified activity class names to be blacklisted in Recents, add package names into overlay as needed -->
     <string-array name="recents_blacklist_array">
@@ -1016,10 +1032,10 @@
     <string name="monitoring_title">Network monitoring</string>
 
     <!-- STOPSHIP Monitoring strings still need to be finalized and approved -->
-    <!-- Monitoring dialog subtitle for the section describing VPN [CHAR LIMIT=TODO]-->
+    <!-- Monitoring dialog subtitle for the section describing VPN [CHAR LIMIT=35]-->
     <string name="monitoring_subtitle_vpn">VPN</string>
 
-    <!-- Monitoring dialog subtitle for the section describing network logging [CHAR LIMIT=TODO]-->
+    <!-- Monitoring dialog subtitle for the section describing network logging [CHAR LIMIT=35]-->
     <string name="monitoring_subtitle_network_logging">Network Logging</string>
 
     <!-- Monitoring dialog disable vpn button [CHAR LIMIT=30] -->
@@ -1035,7 +1051,7 @@
     <string name="monitoring_description_do_header_with_name"><xliff:g id="organization_name" example="Foo, Inc.">%1$s</xliff:g> uses <xliff:g id="device_owner_app" example="Google Mobile Management">%2$s</xliff:g> to manage your device.</string>
 
     <!-- Monitoring dialog: Part of text body explaining what a Device Owner app can do [CHAR LIMIT=130] -->
-    <string name="monitoring_description_do_body">Your administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.</string>
+    <string name="monitoring_description_do_body">Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.</string>
 
     <!-- Monitoring dialog: Space that separates the body text and the "learn more" link that follows it. [CHAR LIMIT=5] -->
     <string name="monitoring_description_do_learn_more_separator">" "</string>
@@ -1049,18 +1065,18 @@
     <!-- Monitoring dialog: Space that separates the VPN body text and the "Open VPN Settings" link that follows it. [CHAR LIMIT=5] -->
     <string name="monitoring_description_vpn_settings_separator">" "</string>
 
-    <!-- Monitoring dialog: Link to open the VPN settings page [CHAR LIMIT=TODO] -->
+    <!-- Monitoring dialog: Link to open the VPN settings page [CHAR LIMIT=60] -->
     <string name="monitoring_description_vpn_settings">Open VPN Settings</string>
 
-    <!-- Monitoring dialog: Network logging text [CHAR LIMIT=TODO] -->
-    <string name="monitoring_description_network_logging">Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information contact your admin.</string>
+    <!-- Monitoring dialog: Network logging text [CHAR LIMIT=400] -->
+    <string name="monitoring_description_network_logging">Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information, contact your admin.</string>
 
 
     <!-- Monitoring dialog VPN text [CHAR LIMIT=400] -->
     <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps, and websites.</string>
 
     <!-- Monitoring dialog VPN with profile owner text [CHAR LIMIT=400] -->
-    <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your administrator.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>
+    <string name="monitoring_description_vpn_profile_owned">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour admin is capable of monitoring your network activity including emails, apps, and websites.\n\nFor more information, contact your admin.\n\nYou\'re also connected to a VPN, which can monitor your network activity.</string>
 
     <!-- Name for a generic legacy VPN connection [CHAR LIMIT=20] -->
     <string name="legacy_vpn_name">VPN</string>
@@ -1075,7 +1091,7 @@
     <string name="branded_monitoring_description_app_personal">You\'re connected to <xliff:g id="application">%1$s</xliff:g>, which can monitor your personal network activity, including emails, apps, and websites.</string>
 
     <!-- Monitoring dialog text for single app (inside work profile) [CHAR LIMIT=400] -->
-    <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your administrator.</string>
+    <string name="monitoring_description_app_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nFor more information, contact your admin.</string>
 
     <!-- Monitoring dialog text for multiple apps (in personal and work profiles) [CHAR LIMIT=400] -->
     <string name="monitoring_description_app_personal_work">Your work profile is managed by <xliff:g id="organization">%1$s</xliff:g>. It is connected to <xliff:g id="application_work">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps, and websites.\n\nYou\'re also connected to <xliff:g id="application_personal">%3$s</xliff:g>, which can monitor your personal network activity.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a9c858c..6535a81 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -93,37 +93,34 @@
         <item name="android:textColor">#FF808080</item>
     </style>
 
-    <style name="TextAppearance.StatusBar.TextButton"
-        parent="@*android:style/TextAppearance.StatusBar">
-        <item name="android:textAppearance">?android:attr/textAppearance</item>
-        <item name="android:textStyle">normal</item>
-        <item name="android:textColor">#FFFFFFFF</item>
-    </style>
-
     <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon">
         <item name="android:textSize">@dimen/status_bar_clock_size</item>
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textColor">@color/status_bar_clock_color</item>
     </style>
 
-    <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar" />
+    <style name="TextAppearance.StatusBar.Expanded" parent="@*android:style/TextAppearance.StatusBar">
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
+    </style>
 
     <style name="TextAppearance.StatusBar.Expanded.Clock">
         <item name="android:textSize">@dimen/qs_time_expanded_size</item>
-        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textStyle">normal</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.Date">
         <item name="android:textSize">@dimen/qs_date_collapsed_size</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.AboveDateTime">
         <item name="android:textSize">@dimen/qs_emergency_calls_only_text_size</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
+        <item name="android:textColor">?android:attr/textColorTertiary</item>
     </style>
 
     <style name="TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
@@ -135,7 +132,7 @@
     <style name="TextAppearance.StatusBar.Expanded.UserSwitcher">
         <item name="android:textSize">16sp</item>
         <item name="android:textStyle">normal</item>
-        <item name="android:textColor">@color/qs_user_detail_name</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
     <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.UserName" />
 
@@ -172,7 +169,7 @@
 
     <style name="TextAppearance.QS.DetailButton">
         <item name="android:textSize">@dimen/qs_detail_button_text_size</item>
-        <item name="android:textColor">@color/qs_detail_button</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textAllCaps">true</item>
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:gravity">center</item>
@@ -184,7 +181,7 @@
 
     <style name="TextAppearance.QS.DetailEmpty">
         <item name="android:textSize">@dimen/qs_detail_empty_text_size</item>
-        <item name="android:textColor">@color/qs_subhead</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
     <style name="TextAppearance.QS.Subhead">
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/ActivityStarter.java
new file mode 100644
index 0000000..a4d8a10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarter.java
@@ -0,0 +1,38 @@
+/*
+ * 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.app.PendingIntent;
+import android.content.Intent;
+
+/**
+ * An interface to start activities. This is used as a callback from the views to
+ * {@link PhoneStatusBar} to allow custom handling for starting the activity, i.e. dismissing the
+ * Keyguard.
+ */
+public interface ActivityStarter {
+
+    void startPendingIntentDismissingKeyguard(PendingIntent intent);
+    void startActivity(Intent intent, boolean dismissShade);
+    void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
+    void startActivity(Intent intent, boolean dismissShade, Callback callback);
+    void postStartActivityDismissingKeyguard(Intent intent, int delay);
+    void postStartActivityDismissingKeyguard(PendingIntent intent);
+    void postQSRunnableDismissingKeyguard(Runnable runnable);
+
+    interface Callback {
+        void onActivityStarted(int resultCode);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
new file mode 100644
index 0000000..4ae81a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ActivityStarterDelegate.java
@@ -0,0 +1,73 @@
+/*
+ * 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.app.PendingIntent;
+import android.content.Intent;
+
+/**
+ * Single common instance of ActivityStarter that can be gotten and referenced from anywhere, but
+ * delegates to an actual implementation such as PhoneStatusBar, assuming it exists.
+ */
+public class ActivityStarterDelegate implements ActivityStarter {
+
+    private ActivityStarter mActualStarter;
+
+    @Override
+    public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
+        if (mActualStarter == null) return;
+        mActualStarter.startPendingIntentDismissingKeyguard(intent);
+    }
+
+    @Override
+    public void startActivity(Intent intent, boolean dismissShade) {
+        if (mActualStarter == null) return;
+        mActualStarter.startActivity(intent, dismissShade);
+    }
+
+    @Override
+    public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
+        if (mActualStarter == null) return;
+        mActualStarter.startActivity(intent, onlyProvisioned, dismissShade);
+    }
+
+    @Override
+    public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
+        if (mActualStarter == null) return;
+        mActualStarter.startActivity(intent, dismissShade, callback);
+    }
+
+    @Override
+    public void postStartActivityDismissingKeyguard(Intent intent, int delay) {
+        if (mActualStarter == null) return;
+        mActualStarter.postStartActivityDismissingKeyguard(intent, delay);
+    }
+
+    @Override
+    public void postStartActivityDismissingKeyguard(PendingIntent intent) {
+        if (mActualStarter == null) return;
+        mActualStarter.postStartActivityDismissingKeyguard(intent);
+    }
+
+    @Override
+    public void postQSRunnableDismissingKeyguard(Runnable runnable) {
+        if (mActualStarter == null) return;
+        mActualStarter.postQSRunnableDismissingKeyguard(runnable);
+    }
+
+    public void setActivityStarterImpl(ActivityStarter starter) {
+        mActualStarter = starter;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 07ef5e0..5a6afca 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -292,12 +292,16 @@
         }
         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();
-        mOldDarkIntensity = darkIntensity;
     }
 
     private int getBackgroundColor(float darkIntensity) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index ef1c25d..b30b596 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -72,6 +72,8 @@
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
+        mBatteryController = Dependency.get(BatteryController.class);
+        mDrawable.setBatteryController(mBatteryController);
         mBatteryController.addCallback(this);
         mDrawable.startListening();
         TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
@@ -97,12 +99,11 @@
 
     }
 
-    public void setBatteryController(BatteryController mBatteryController) {
-        this.mBatteryController = mBatteryController;
-        mDrawable.setBatteryController(mBatteryController);
-    }
-
     public void setDarkIntensity(float f) {
         mDrawable.setDarkIntensity(f);
     }
+
+    public void setRawColors(int fgColor, int bgColor) {
+        mDrawable.setColors(fgColor, bgColor);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java b/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java
new file mode 100644
index 0000000..4fba640
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java
@@ -0,0 +1,21 @@
+/*
+ * 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.content.res.Configuration;
+
+public interface ConfigurationChangedReceiver {
+    void onConfigurationChanged(Configuration newConfiguration);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
new file mode 100644
index 0000000..135b129
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.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;
+
+import android.content.res.Configuration;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
+import com.android.systemui.statusbar.policy.AccessibilityController;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
+import com.android.systemui.statusbar.policy.BluetoothController;
+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.DataSaverController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.HotspotControllerImpl;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationControllerImpl;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkControllerImpl;
+import com.android.systemui.statusbar.policy.NextAlarmController;
+import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Class to handle ugly dependencies throughout sysui until we determine the
+ * long-term dependency injection solution.
+ *
+ * Classes added here should be things that are expected to live the lifetime of sysui,
+ * and are generally applicable to many parts of sysui. They will be lazily
+ * initialized to ensure they aren't created on form factors that don't need them
+ * (e.g. HotspotController on TV). Despite being lazily initialized, it is expected
+ * that all dependencies will be gotten during sysui startup, and not during runtime
+ * to avoid jank.
+ *
+ * All classes used here are expected to manage their own lifecycle, meaning if
+ * they have no clients they should not have any registered resources like bound
+ * services, registered receivers, etc.
+ */
+public class Dependency extends SystemUI {
+
+    /**
+     * Key for getting a background Looper for background work.
+     */
+    public static final String BG_LOOPER = "background_loooper";
+    /**
+     * Key for getting a Handler for receiving time tick broadcasts on.
+     */
+    public static final String TIME_TICK_HANDLER = "time_tick_handler";
+    /**
+     * Generic handler on the main thread.
+     */
+    public static final String MAIN_HANDLER = "main_handler";
+
+    private final ArrayMap<String, Object> mDependencies = new ArrayMap<>();
+    private final ArrayMap<String, DependencyProvider> mProviders = new ArrayMap<>();
+
+    @Override
+    public void start() {
+        sDependency = this;
+        // TODO: Think about ways to push these creation rules out of Dependency to cut down
+        // on imports.
+        mProviders.put(TIME_TICK_HANDLER, () -> {
+            HandlerThread thread = new HandlerThread("TimeTick");
+            thread.start();
+            return new Handler(thread.getLooper());
+        });
+        mProviders.put(BG_LOOPER, () -> {
+            HandlerThread thread = new HandlerThread("SysUiBg",
+                    Process.THREAD_PRIORITY_BACKGROUND);
+            thread.start();
+            return thread.getLooper();
+        });
+        mProviders.put(MAIN_HANDLER, () -> new Handler(Looper.getMainLooper()));
+        mProviders.put(ActivityStarter.class.getName(), () -> new ActivityStarterDelegate());
+        mProviders.put(ActivityStarterDelegate.class.getName(), () ->
+                getDependency(ActivityStarter.class));
+
+        mProviders.put(BluetoothController.class.getName(), () ->
+                new BluetoothControllerImpl(mContext, getDependency(BG_LOOPER)));
+
+        mProviders.put(LocationController.class.getName(), () ->
+                new LocationControllerImpl(mContext, getDependency(BG_LOOPER)));
+
+        mProviders.put(RotationLockController.class.getName(), () ->
+                new RotationLockControllerImpl(mContext));
+
+        mProviders.put(NetworkController.class.getName(), () ->
+                new NetworkControllerImpl(mContext, getDependency(BG_LOOPER),
+                        getDependency(DeviceProvisionedController.class)));
+
+        mProviders.put(ZenModeController.class.getName(), () ->
+                new ZenModeControllerImpl(mContext, getDependency(MAIN_HANDLER)));
+
+        mProviders.put(HotspotController.class.getName(), () ->
+                new HotspotControllerImpl(mContext));
+
+        mProviders.put(CastController.class.getName(), () ->
+                new CastControllerImpl(mContext));
+
+        mProviders.put(FlashlightController.class.getName(), () ->
+                new FlashlightControllerImpl(mContext));
+
+        mProviders.put(KeyguardMonitor.class.getName(), () ->
+                new KeyguardMonitorImpl(mContext));
+
+        mProviders.put(UserSwitcherController.class.getName(), () ->
+                new UserSwitcherController(mContext, getDependency(KeyguardMonitor.class),
+                        getDependency(MAIN_HANDLER), getDependency(ActivityStarter.class)));
+
+        mProviders.put(UserInfoController.class.getName(), () ->
+                new UserInfoControllerImpl(mContext));
+
+        mProviders.put(BatteryController.class.getName(), () ->
+                new BatteryControllerImpl(mContext));
+
+        mProviders.put(ManagedProfileController.class.getName(), () ->
+                new ManagedProfileControllerImpl(mContext));
+
+        mProviders.put(NextAlarmController.class.getName(), () ->
+                new NextAlarmControllerImpl(mContext));
+
+        mProviders.put(DataSaverController.class.getName(), () ->
+                get(NetworkController.class).getDataSaverController());
+
+        mProviders.put(AccessibilityController.class.getName(), () ->
+                new AccessibilityController(mContext));
+
+        mProviders.put(DeviceProvisionedController.class.getName(), () ->
+                new DeviceProvisionedControllerImpl(mContext));
+
+        mProviders.put(AssistManager.class.getName(), () ->
+                new AssistManager(getDependency(DeviceProvisionedController.class), mContext));
+
+        mProviders.put(SecurityController.class.getName(), () ->
+                new SecurityControllerImpl(mContext));
+
+        // Put all dependencies above here so the factory can override them if it wants.
+        SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        super.dump(fd, pw, args);
+        pw.println("Dumping existing controllers:");
+        mDependencies.values().stream().filter(obj -> obj instanceof Dumpable)
+                .forEach(o -> ((Dumpable) o).dump(fd, pw, args));
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        mDependencies.values().stream().filter(obj -> obj instanceof ConfigurationChangedReceiver)
+                .forEach(o -> ((ConfigurationChangedReceiver) o).onConfigurationChanged(newConfig));
+    }
+
+    protected final <T> T getDependency(Class<T> cls) {
+        return getDependency(cls.getName());
+    }
+
+    protected final <T> T getDependency(String cls) {
+        T obj = (T) mDependencies.get(cls);
+        if (obj == null) {
+            obj = createDependency(cls);
+            mDependencies.put(cls, obj);
+        }
+        return obj;
+    }
+
+    @VisibleForTesting
+    protected <T> T createDependency(String cls) {
+        DependencyProvider<T> provider = mProviders.get(cls);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unsupported dependency " + cls);
+        }
+        return provider.createDependency();
+    }
+
+    private static Dependency sDependency;
+
+    public interface DependencyProvider<T> {
+        T createDependency();
+    }
+
+    public static <T> T get(Class<T> cls) {
+        return sDependency.getDependency(cls.getName());
+    }
+
+    public static <T> T get(String cls) {
+        return sDependency.getDependency(cls);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Dumpable.java b/packages/SystemUI/src/com/android/systemui/Dumpable.java
new file mode 100644
index 0000000..65a6844
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/Dumpable.java
@@ -0,0 +1,22 @@
+/*
+ * 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 java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public interface Dumpable {
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index d98bb23..8141b28 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -326,7 +326,7 @@
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 if (DEBUG) Log.d(TAG, "up/cancel");
-                finishExpanding(ev.getActionMasked() == MotionEvent.ACTION_CANCEL,
+                finishExpanding(ev.getActionMasked() == MotionEvent.ACTION_CANCEL /* forceAbort */,
                         getCurrentVelocity());
                 clearView();
                 break;
@@ -587,6 +587,9 @@
             mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity);
             mScaleAnimation.start();
         } else {
+            if (targetHeight != currentHeight) {
+                mScaler.setHeight(targetHeight);
+            }
             mCallback.setUserExpandedChild(mResizedView, nowExpanded);
             mCallback.setUserLockedChild(mResizedView, false);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
index efa7cae..efddf20 100644
--- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public void onPluginConnected(ViewProvider plugin) {
+    public void onPluginConnected(ViewProvider plugin, Context context) {
         mPluginView = plugin.getView();
         inflateLayout();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
index c4470cd..ff4b7cb 100644
--- a/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
@@ -14,10 +14,16 @@
 
 package com.android.systemui;
 
+import android.content.Context;
+
 /**
  * The interface for getting core components of SysUI. Exists for Testability
  * since tests don't have SystemUIApplication as their ApplicationContext.
  */
 public interface SysUiServiceProvider {
     <T> T getComponent(Class<T> interfaceType);
+
+    public static <T> T getComponent(Context context, Class<T> interfaceType) {
+        return ((SysUiServiceProvider) context.getApplicationContext()).getComponent(interfaceType);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index bd4e3dc..f2aaec1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -29,7 +29,6 @@
 import android.os.UserHandle;
 import android.util.Log;
 
-import com.android.systemui.doze.DozeFactory;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyboard.KeyboardUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -64,6 +63,7 @@
      * The classes of the stuff to start.
      */
     private final Class<?>[] SERVICES = new Class[] {
+            Dependency.class,
             FragmentService.class,
             TunerService.class,
             CommandQueue.CommandQueueStart.class,
@@ -207,7 +207,7 @@
         PluginManager.getInstance(this).addPluginListener(OverlayPlugin.ACTION,
                 new PluginListener<OverlayPlugin>() {
             @Override
-            public void onPluginConnected(OverlayPlugin plugin) {
+            public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
                 PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
                 if (phoneStatusBar != null) {
                     plugin.setup(phoneStatusBar.getStatusBarWindow(),
@@ -239,8 +239,4 @@
     public SystemUI[] getServices() {
         return mServices;
     }
-
-    public static <T> T getComponent(Context context, Class<T> interfaceType) {
-        return ((SysUiServiceProvider) context.getApplicationContext()).getComponent(interfaceType);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 10328a4..228996a 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -18,12 +18,14 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.Dependency.DependencyProvider;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -114,24 +116,14 @@
     }
 
     public QSTileHost createQSTileHost(Context context, PhoneStatusBar statusBar,
-            BluetoothController bluetooth, LocationController location,
-            RotationLockController rotation, NetworkController network,
-            ZenModeController zen, HotspotController hotspot,
-            CastController cast, FlashlightController flashlight,
-            UserSwitcherController userSwitcher, UserInfoController userInfo,
-            KeyguardMonitor keyguard, SecurityController security,
-            BatteryController battery, StatusBarIconController iconController,
-            NextAlarmController nextAlarmController) {
-        return new QSTileHost(context, statusBar, bluetooth, location, rotation, network, zen,
-                hotspot, cast, flashlight, userSwitcher, userInfo, keyguard, security, battery,
-                iconController, nextAlarmController);
+            StatusBarIconController iconController) {
+        return new QSTileHost(context, statusBar, iconController);
     }
 
     public <T> T createInstance(Class<T> classType) {
         return null;
     }
 
-    public AssistManager createAssistManager(BaseStatusBar bar, Context context) {
-        return new AssistManager(bar, context);
-    }
+    public void injectDependencies(ArrayMap<String, DependencyProvider> providers,
+            Context context) { }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 05e5f6b..11e0f28 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -18,7 +18,9 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.os.Build;
 import android.os.IBinder;
+import android.os.SystemProperties;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -29,6 +31,11 @@
     public void onCreate() {
         super.onCreate();
         ((SystemUIApplication) getApplication()).startServicesIfNeeded();
+
+        // For debugging RescueParty
+        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
+            throw new RuntimeException();
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 2576bb7..09fdf5a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -9,14 +9,15 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -33,14 +34,17 @@
 import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.settingslib.applications.InterestingConfigChanges;
+import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 /**
  * Class to manage everything related to assist in SystemUI.
  */
-public class AssistManager {
+public class AssistManager implements ConfigurationChangedReceiver {
 
     private static final String TAG = "AssistManager";
     private static final String ASSIST_ICON_METADATA_NAME =
@@ -52,9 +56,10 @@
     protected final Context mContext;
     private final WindowManager mWindowManager;
     private final AssistDisclosure mAssistDisclosure;
+    private final InterestingConfigChanges mInterestingConfigChanges;
 
     private AssistOrbContainer mView;
-    private final BaseStatusBar mBar;
+    private final DeviceProvisionedController mDeviceProvisionedController;
     protected final AssistUtils mAssistUtils;
 
     private IVoiceInteractionSessionShowCallback mShowCallback =
@@ -79,14 +84,16 @@
         }
     };
 
-    public AssistManager(BaseStatusBar bar, Context context) {
+    public AssistManager(DeviceProvisionedController controller, Context context) {
         mContext = context;
-        mBar = bar;
+        mDeviceProvisionedController = controller;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mAssistUtils = new AssistUtils(context);
         mAssistDisclosure = new AssistDisclosure(context, new Handler());
 
         registerVoiceInteractionSessionListener();
+        mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION);
+        onConfigurationChanged(context.getResources().getConfiguration());
     }
 
     protected void registerVoiceInteractionSessionListener() {
@@ -104,7 +111,10 @@
         });
     }
 
-    public void onConfigurationChanged() {
+    public void onConfigurationChanged(Configuration newConfiguration) {
+        if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) {
+            return;
+        }
         boolean visible = false;
         if (mView != null) {
             visible = mView.isShowing();
@@ -183,13 +193,13 @@
     }
 
     private void startAssistActivity(Bundle args, @NonNull ComponentName assistComponent) {
-        if (!mBar.isDeviceProvisioned()) {
+        if (!mDeviceProvisionedController.isDeviceProvisioned()) {
             return;
         }
 
         // Close Recent Apps if needed
-        mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL |
-                CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
+        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).animateCollapsePanels(
+                CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL | CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
 
         boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, UserHandle.USER_CURRENT) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index e081b53..00d2298 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -37,7 +37,7 @@
 
     interface Callback {
         default void onNewNotifications() {}
-        default void onBuzzBeepBlinked() {}
+        default void onNotificationHeadsUp() {}
         default void onNotificationLight(boolean on) {}
         default void onPowerSaveChanged(boolean active) {}
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 84b22ea..db5a392 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -309,7 +309,7 @@
 
     private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
-        public void onBuzzBeepBlinked() {
+        public void onNotificationHeadsUp() {
             onNotification();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 57857cc..50506a9 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -27,11 +27,13 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Parcelable;
+import android.util.ArrayMap;
 import android.view.LayoutInflater;
 import android.view.View;
 
 import com.android.settingslib.applications.InterestingConfigChanges;
 import com.android.systemui.SystemUIApplication;
+import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginManager;
 
 import java.io.FileDescriptor;
@@ -47,6 +49,7 @@
     private final View mRootView;
     private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges();
     private final FragmentService mManager;
+    private final PluginFragmentManager mPlugins = new PluginFragmentManager();
 
     private FragmentController mFragments;
     private FragmentLifecycleCallbacks mLifecycleCallbacks;
@@ -163,6 +166,10 @@
         return mFragments.getFragmentManager();
     }
 
+    PluginFragmentManager getPluginManager() {
+        return mPlugins;
+    }
+
     public interface FragmentListener {
         void onFragmentViewCreated(String tag, Fragment fragment);
 
@@ -198,6 +205,11 @@
         }
 
         @Override
+        public Fragment instantiate(Context context, String className, Bundle arguments) {
+            return mPlugins.instantiate(context, className, arguments);
+        }
+
+        @Override
         public boolean onShouldSaveFragmentState(Fragment fragment) {
             return true; // True for now.
         }
@@ -237,4 +249,57 @@
             return true;
         }
     }
+
+    class PluginFragmentManager {
+        private final ArrayMap<String, Context> mPluginLookup = new ArrayMap<>();
+
+        public void removePlugin(String tag, String currentClass, String defaultClass) {
+            Fragment fragment = getFragmentManager().findFragmentByTag(tag);
+            mPluginLookup.remove(currentClass);
+            getFragmentManager().beginTransaction()
+                    .replace(((View) fragment.getView().getParent()).getId(),
+                            instantiate(mContext, defaultClass, null), tag)
+                    .commit();
+            reloadFragments();
+        }
+
+        public void setCurrentPlugin(String tag, String currentClass, Context context) {
+            Fragment fragment = getFragmentManager().findFragmentByTag(tag);
+            mPluginLookup.put(currentClass, context);
+            getFragmentManager().beginTransaction()
+                    .replace(((View) fragment.getView().getParent()).getId(),
+                            instantiate(context, currentClass, null), tag)
+                    .commit();
+            reloadFragments();
+        }
+
+        private void reloadFragments() {
+            // Save the old state.
+            Parcelable p = destroyFragmentHost();
+            // Generate a new fragment host and restore its state.
+            createFragmentHost(p);
+        }
+
+        Fragment instantiate(Context context, String className, Bundle arguments) {
+            Context pluginContext = mPluginLookup.get(className);
+            if (pluginContext != null) {
+                Fragment f = Fragment.instantiate(pluginContext, className, arguments);
+                if (f instanceof Plugin) {
+                    ((Plugin) f).onCreate(mContext, pluginContext);
+                }
+                return f;
+            }
+            return Fragment.instantiate(context, className, arguments);
+        }
+    }
+
+    private static class PluginState {
+        Context mContext;
+        String mCls;
+
+        private PluginState(String cls, Context context) {
+            mCls = cls;
+            mContext = context;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
index e107fcd..2e6de4a 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
@@ -15,6 +15,7 @@
 package com.android.systemui.fragments;
 
 import android.app.Fragment;
+import android.content.Context;
 import android.util.Log;
 import android.view.View;
 
@@ -30,27 +31,19 @@
     private final FragmentHostManager mFragmentHostManager;
     private final PluginManager mPluginManager;
     private final Class<? extends Fragment> mDefaultClass;
-    private final int mId;
-    private final String mTag;
     private final Class<? extends FragmentBase> mExpectedInterface;
+    private final String mTag;
 
-    public PluginFragmentListener(View view, String tag, int id,
-            Class<? extends Fragment> defaultFragment,
+    public PluginFragmentListener(View view, String tag, Class<? extends Fragment> defaultFragment,
             Class<? extends FragmentBase> expectedInterface) {
+        mTag = tag;
         mFragmentHostManager = FragmentHostManager.get(view);
         mPluginManager = PluginManager.getInstance(view.getContext());
         mExpectedInterface = expectedInterface;
-        mTag = tag;
         mDefaultClass = defaultFragment;
-        mId = id;
     }
 
     public void startListening(String action, int version) {
-        try {
-            setFragment(mDefaultClass.newInstance());
-        } catch (InstantiationException | IllegalAccessException e) {
-            Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
-        }
         mPluginManager.addPluginListener(action, this, version, false /* Only allow one */);
     }
 
@@ -58,17 +51,13 @@
         mPluginManager.removePluginListener(this);
     }
 
-    private void setFragment(Fragment fragment) {
-        mFragmentHostManager.getFragmentManager().beginTransaction()
-                .replace(mId, fragment, mTag)
-                .commit();
-    }
-
     @Override
-    public void onPluginConnected(Plugin plugin) {
+    public void onPluginConnected(Plugin plugin, Context pluginContext) {
         try {
             mExpectedInterface.cast(plugin);
-            setFragment((Fragment) plugin);
+            Fragment.class.cast(plugin);
+            mFragmentHostManager.getPluginManager().setCurrentPlugin(mTag,
+                    plugin.getClass().getName(), pluginContext);
         } catch (ClassCastException e) {
             Log.e(TAG, plugin.getClass().getName() + " must be a Fragment and implement "
                     + mExpectedInterface.getName(), e);
@@ -77,10 +66,7 @@
 
     @Override
     public void onPluginDisconnected(Plugin plugin) {
-        try {
-            setFragment(mDefaultClass.newInstance());
-        } catch (InstantiationException | IllegalAccessException e) {
-            Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
-        }
+        mFragmentHostManager.getPluginManager().removePlugin(mTag,
+                plugin.getClass().getName(), mDefaultClass.getName());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 63d1cc2..c7514a9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -91,10 +91,6 @@
         // Draw captions overlaid on the content view, so the whole window is one solid color.
         setOverlayWithDecorCaptionEnabled(true);
 
-        // Match task description to the task stack we are replacing so it's still recognizably the
-        // original task stack with the same icon and title text.
-        setTaskDescription(new TaskDescription(null, null, color));
-
         // Blank out the activity. When it is on-screen it will look like a Recents thumbnail with
         // redaction switched on.
         final View blankView = new View(this);
@@ -127,6 +123,11 @@
         return;
     }
 
+    @Override
+    public void setTaskDescription(TaskDescription taskDescription) {
+        // Use the previous activity's task description.
+    }
+
     private final BroadcastReceiver mLockEventReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 728d558..9788903 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -22,6 +22,7 @@
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
+import android.media.PlayerBase;
 import android.net.Uri;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -81,6 +82,12 @@
                     (AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
                 try {
                     MediaPlayer player = new MediaPlayer();
+                    if (mCmd.attributes == null) {
+                        mCmd.attributes = new AudioAttributes.Builder()
+                                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
+                                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                                .build();
+                    }
                     player.setAudioAttributes(mCmd.attributes);
                     player.setDataSource(mCmd.context, mCmd.uri);
                     player.setLooping(mCmd.looping);
@@ -92,13 +99,11 @@
                                 if (mAudioManagerWithAudioFocus == null) {
                                     if (mDebug) Log.d(mTag, "requesting AudioFocus");
                                     if (mCmd.looping) {
-                                        audioManager.requestAudioFocus(null,
-                                                AudioAttributes.toLegacyStreamType(mCmd.attributes),
-                                                AudioManager.AUDIOFOCUS_GAIN);
+                                        audioManager.requestAudioFocus(null, mCmd.attributes,
+                                                AudioManager.AUDIOFOCUS_GAIN, 0);
                                     } else {
-                                        audioManager.requestAudioFocus(null,
-                                                AudioAttributes.toLegacyStreamType(mCmd.attributes),
-                                                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+                                        audioManager.requestAudioFocus(null, mCmd.attributes,
+                                                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
                                     }
                                     mAudioManagerWithAudioFocus = audioManager;
                                 } else {
@@ -296,6 +301,7 @@
      */
     @Deprecated
     public void play(Context context, Uri uri, boolean looping, int stream) {
+        PlayerBase.deprecateStreamTypeForPlayback(stream, "NotificationPlayer", "play");
         Command cmd = new Command();
         cmd.requestTime = SystemClock.uptimeMillis();
         cmd.code = PLAY;
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 a2d7d6b..3103267 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,14 +16,20 @@
 
 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.os.Handler;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
@@ -49,6 +55,7 @@
     private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
     private PipMenuActivityController mMenuController;
+    private PipMediaController mMediaController;
     private PipTouchHandler mTouchHandler;
 
     /**
@@ -57,7 +64,11 @@
     TaskStackListener mTaskStackListener = new TaskStackListener() {
         @Override
         public void onActivityPinned() {
+            if (!checkCurrentUserId(false /* debug */)) {
+                return;
+            }
             mTouchHandler.onActivityPinned();
+            mMediaController.onActivityPinned();
         }
 
         @Override
@@ -66,8 +77,24 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt() {
-            // TODO(winsonc): Hide the menu and expand the PiP
+        public void onPinnedActivityRestartAttempt(ComponentName sourceComponent) {
+            if (!checkCurrentUserId(false /* debug */)) {
+                return;
+            }
+
+            // Expand the activity back to fullscreen only if it was attempted to be restarted from
+            // another package than the top activity in the stack
+            boolean expandPipToFullscreen = true;
+            if (sourceComponent != null) {
+                ComponentName topActivity = PipUtils.getTopPinnedActivity(mActivityManager);
+                expandPipToFullscreen = topActivity != null && topActivity.getPackageName().equals(
+                        sourceComponent.getPackageName());
+            }
+            if (expandPipToFullscreen) {
+                mTouchHandler.expandPinnedStackToFullscreen();
+            } else {
+                Log.w(TAG, "Can not expand PiP to fullscreen via intent from the same package.");
+            }
         }
     };
 
@@ -91,7 +118,7 @@
         @Override
         public void onActionsChanged(ParceledListSlice actions) {
             mHandler.post(() -> {
-                mMenuController.setActions(actions);
+                mMenuController.setAppActions(actions);
             });
         }
 
@@ -127,7 +154,9 @@
         }
         SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
 
-        mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager);
+        mMediaController = new PipMediaController(context, mActivityManager);
+        mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager,
+                mMediaController);
         mTouchHandler = new PipTouchHandler(context, mMenuController, mActivityManager,
                 mWindowManager);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
new file mode 100644
index 0000000..2284013
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -0,0 +1,193 @@
+/*
+ * 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.pip.phone;
+
+import android.app.IActivityManager;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
+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 com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Interfaces with the {@link MediaSessionManager} to compose the right set of actions to show (only
+ * if there are no actions from the PiP activity itself). The active media controller is only set
+ * when there is a media session from the top PiP activity.
+ */
+public class PipMediaController {
+
+    /**
+     * A listener interface to receive notification on changes to the media actions.
+     */
+    public interface ActionListener {
+        /**
+         * Called when the media actions changes.
+         */
+        void onMediaActionsChanged(List<RemoteAction> actions);
+    }
+
+    private final Context mContext;
+    private final IActivityManager mActivityManager;
+
+    private final MediaSessionManager mMediaSessionManager;
+    private MediaController mMediaController;
+
+    private RemoteAction mPauseAction;
+    private RemoteAction mPlayAction;
+
+    private MediaController.Callback mPlaybackChangedListener = new MediaController.Callback() {
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            if (!mListeners.isEmpty()) {
+                notifyActionsChanged(getMediaActions());
+            }
+        }
+    };
+
+    private ArrayList<ActionListener> mListeners = new ArrayList<>();
+
+    public PipMediaController(Context context, IActivityManager activityManager) {
+        mContext = context;
+        mActivityManager = activityManager;
+
+        createMediaActions();
+        mMediaSessionManager =
+                (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
+        mMediaSessionManager.addOnActiveSessionsChangedListener(controllers -> {
+            resolveActiveMediaController(controllers);
+        }, null);
+    }
+
+    /**
+     * Handles when an activity is pinned.
+     */
+    public void onActivityPinned() {
+        // Once we enter PiP, try to find the active media controller for the top most activity
+        resolveActiveMediaController(mMediaSessionManager.getActiveSessions(null));
+    }
+
+    /**
+     * Adds a new media action listener.
+     */
+    public void addListener(ActionListener listener) {
+        if (!mListeners.contains(listener)) {
+            mListeners.add(listener);
+            listener.onMediaActionsChanged(getMediaActions());
+        }
+    }
+
+    /**
+     * Removes a media action listener.
+     */
+    public void removeListener(ActionListener listener) {
+        listener.onMediaActionsChanged(Collections.EMPTY_LIST);
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Gets the set of media actions currently available.
+     */
+    private List<RemoteAction> getMediaActions() {
+        if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+            return Collections.EMPTY_LIST;
+        }
+
+        ArrayList<RemoteAction> mediaActions = new ArrayList<>();
+        int state = mMediaController.getPlaybackState().getState();
+        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);
+        }
+        return mediaActions;
+    }
+
+    /**
+     * Creates the standard media buttons that we may show.
+     */
+    private void createMediaActions() {
+        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());
+
+        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());
+    }
+
+    /**
+     * Tries to find and set the active media controller for the top PiP activity.
+     */
+    private void resolveActiveMediaController(List<MediaController> controllers) {
+        if (controllers != null) {
+            final ComponentName topActivity = PipUtils.getTopPinnedActivity(mActivityManager);
+            if (topActivity != null) {
+                for (int i = 0; i < controllers.size(); i++) {
+                    final MediaController controller = controllers.get(i);
+                    if (controller.getPackageName().equals(topActivity.getPackageName())) {
+                        setActiveMediaController(controller);
+                        return;
+                    }
+                }
+            }
+        }
+        setActiveMediaController(null);
+    }
+
+    /**
+     * Sets the active media controller for the top PiP activity.
+     */
+    private void setActiveMediaController(MediaController controller) {
+        if (controller != mMediaController) {
+            if (mMediaController != null) {
+                mMediaController.unregisterCallback(mPlaybackChangedListener);
+            }
+            mMediaController = controller;
+            if (controller != null) {
+                controller.registerCallback(mPlaybackChangedListener);
+            }
+            if (!mListeners.isEmpty()) {
+                notifyActionsChanged(getMediaActions());
+            }
+
+            // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
+        }
+    }
+
+    /**
+     * Notifies all listeners that the actions have changed.
+     */
+    private void notifyActionsChanged(List<RemoteAction> actions) {
+        if (!mListeners.isEmpty()) {
+            mListeners.forEach(l -> l.onMediaActionsChanged(actions));
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 0f7647d..6ef30c0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -1,3 +1,19 @@
+/*
+ * 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;
@@ -5,6 +21,7 @@
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
+import android.app.RemoteAction;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
@@ -16,11 +33,20 @@
 import android.util.Log;
 import android.view.IWindowManager;
 
-import java.util.ArrayList;
+import com.android.systemui.pip.phone.PipMediaController.ActionListener;
 
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the PiP menu activity.
+ *
+ * The current media session provides actions whenever there are no valid actions provided by the
+ * current PiP activity. Otherwise, those actions always take precedence.
+ */
 public class PipMenuActivityController {
 
-    private static final String TAG = "PipMenuActivityController";
+    private static final String TAG = "PipMenuActController";
 
     public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
     public static final String EXTRA_ACTIONS = "actions";
@@ -59,9 +85,12 @@
     private Context mContext;
     private IActivityManager mActivityManager;
     private IWindowManager mWindowManager;
+    private PipMediaController mMediaController;
 
     private ArrayList<Listener> mListeners = new ArrayList<>();
-    private ParceledListSlice mActions;
+    private ParceledListSlice mAppActions;
+    private ParceledListSlice mMediaActions;
+    private boolean mVisible;
 
     private Messenger mToActivityMessenger;
     private Messenger mMessenger = new Messenger(new Handler() {
@@ -70,13 +99,13 @@
             switch (msg.what) {
                 case MESSAGE_MENU_VISIBILITY_CHANGED: {
                     boolean visible = msg.arg1 > 0;
-                    mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible));
+                    onMenuVisibilityChanged(visible);
                     break;
                 }
                 case MESSAGE_EXPAND_PIP: {
                     mListeners.forEach(l -> l.onPipExpand());
                     // Preemptively mark the menu as invisible once we expand the PiP
-                    mListeners.forEach(l -> l.onPipMenuVisibilityChanged(false));
+                    onMenuVisibilityChanged(false);
                     break;
                 }
                 case MESSAGE_MINIMIZE_PIP: {
@@ -86,14 +115,14 @@
                 case MESSAGE_DISMISS_PIP: {
                     mListeners.forEach(l -> l.onPipDismiss());
                     // Preemptively mark the menu as invisible once we dismiss the PiP
-                    mListeners.forEach(l -> l.onPipMenuVisibilityChanged(false));
+                    onMenuVisibilityChanged(false);
                     break;
                 }
                 case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
                     mToActivityMessenger = msg.replyTo;
                     // Mark the menu as invisible once the activity finishes as well
                     if (mToActivityMessenger == null) {
-                        mListeners.forEach(l -> l.onPipMenuVisibilityChanged(false));
+                        onMenuVisibilityChanged(false);
                     }
                     break;
                 }
@@ -101,11 +130,20 @@
         }
     });
 
+    private ActionListener mMediaActionListener = new ActionListener() {
+        @Override
+        public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
+            mMediaActions = new ParceledListSlice<>(mediaActions);
+            updateMenuActions();
+        }
+    };
+
     public PipMenuActivityController(Context context, IActivityManager activityManager,
-            IWindowManager windowManager) {
+            IWindowManager windowManager, PipMediaController mediaController) {
         mContext = context;
         mActivityManager = activityManager;
         mWindowManager = windowManager;
+        mMediaController = mediaController;
     }
 
     /**
@@ -137,7 +175,7 @@
                         pinnedStackInfo.taskIds.length > 0) {
                     Intent intent = new Intent(mContext, PipMenuActivity.class);
                     intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
-                    intent.putExtra(EXTRA_ACTIONS, mActions);
+                    intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
                     ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
                     options.setLaunchTaskId(
                             pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
@@ -168,15 +206,31 @@
     }
 
     /**
-     * Sets the {@param actions} associated with the PiP.
+     * Sets the menu actions to the actions provided by the current PiP activity.
      */
-    public void setActions(ParceledListSlice actions) {
-        mActions = actions;
+    public void setAppActions(ParceledListSlice appActions) {
+        mAppActions = appActions;
+        updateMenuActions();
+    }
 
+    /**
+     * @return the best set of actions to show in the PiP menu.
+     */
+    private ParceledListSlice resolveMenuActions() {
+        if (isValidActions(mAppActions)) {
+            return mAppActions;
+        }
+        return mMediaActions;
+    }
+
+    /**
+     * Updates the PiP menu activity with the best set of actions provided.
+     */
+    private void updateMenuActions() {
         if (mToActivityMessenger != null) {
             Message m = Message.obtain();
             m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
-            m.obj = actions;
+            m.obj = resolveMenuActions();
             try {
                 mToActivityMessenger.send(m);
             } catch (RemoteException e) {
@@ -184,4 +238,30 @@
             }
         }
     }
+
+    /**
+     * Returns whether the set of actions are valid.
+     */
+    private boolean isValidActions(ParceledListSlice actions) {
+        return actions != null && actions.getList().size() > 0;
+    }
+
+    /**
+     * Handles changes in menu visibility.
+     */
+    private void onMenuVisibilityChanged(boolean visible) {
+        mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible));
+        if (visible != mVisible) {
+            if (visible) {
+                // Once visible, start listening for media action changes. This call will trigger
+                // the menu actions to be updated again.
+                mMediaController.addListener(mMediaActionListener);
+            } else {
+                // Once hidden, stop listening for media action changes. This call will trigger
+                // the menu actions to be updated again.
+                mMediaController.removeListener(mMediaActionListener);
+            }
+        }
+        mVisible = visible;
+    }
 }
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 18ae3cf..12fda14 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -87,6 +87,7 @@
     // 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;
@@ -421,7 +422,8 @@
         mContext.getDisplay().getRealSize(displaySize);
         Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mBoundedPinnedStackBounds,
                 mPinnedStackBounds);
-        mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize);
+        mSnapAlgorithm.applyMinimizedOffset(toBounds, mBoundedPinnedStackBounds, displaySize,
+                mStableInsets);
         mPinnedStackBoundsAnimator = mMotionHelper.createAnimationToBounds(mPinnedStackBounds,
                 toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN,
                 mUpdatePinnedStackBoundsListener);
@@ -485,7 +487,7 @@
     /**
      * Resizes the pinned stack back to fullscreen.
      */
-    private void expandPinnedStackToFullscreen() {
+    void expandPinnedStackToFullscreen() {
         BackgroundThread.getHandler().post(() -> {
             try {
                 mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
@@ -528,6 +530,7 @@
                 if (updatePinnedStackBounds) {
                     mPinnedStackBounds.set(info.bounds);
                 }
+                mWindowManager.getStableInsets(info.displayId, mStableInsets);
                 mBoundedPinnedStackBounds.set(mWindowManager.getPictureInPictureMovementBounds(
                         info.displayId));
             }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
new file mode 100644
index 0000000..9c03830
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.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 com.android.systemui.pip.phone;
+
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+
+import android.app.ActivityManager.StackInfo;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class PipUtils {
+
+    private static final String TAG = "PipUtils";
+
+    /**
+     * @return the ComponentName of the top activity in the pinned stack, or null if none exists.
+     */
+    public static ComponentName getTopPinnedActivity(IActivityManager activityManager) {
+        try {
+            StackInfo pinnedStackInfo = activityManager.getStackInfo(PINNED_STACK_ID);
+            if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
+                    pinnedStackInfo.taskIds.length > 0) {
+                return pinnedStackInfo.topActivity;
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Unable to get pinned stack.");
+        }
+        return null;
+    }
+}
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 a622656..56947e5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -590,7 +590,7 @@
         @Override
         public void onTaskStackChanged() {
             if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
-            if (!checkCurrentUserId()) {
+            if (!checkCurrentUserId(DEBUG)) {
                 return;
             }
             if (mState != STATE_NO_PIP) {
@@ -627,7 +627,7 @@
         @Override
         public void onActivityPinned() {
             if (DEBUG) Log.d(TAG, "onActivityPinned()");
-            if (!checkCurrentUserId()) {
+            if (!checkCurrentUserId(DEBUG)) {
                 return;
             }
             StackInfo stackInfo = getPinnedStackInfo();
@@ -658,9 +658,9 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt() {
+        public void onPinnedActivityRestartAttempt(ComponentName sourceComponent) {
             if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
-            if (!checkCurrentUserId()) {
+            if (!checkCurrentUserId(DEBUG)) {
                 return;
             }
             // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
@@ -670,7 +670,7 @@
         @Override
         public void onPinnedStackAnimationEnded() {
             if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
-            if (!checkCurrentUserId()) {
+            if (!checkCurrentUserId(DEBUG)) {
                 return;
             }
             switch (mState) {
@@ -693,26 +693,6 @@
                     break;
             }
         }
-
-        // {@link android.app.ITaskStackListener} isn't multi-user aware.
-        // Check the current uid and current SystemUI's running uid
-        // so we can handle the PIP status change only once.
-        private boolean checkCurrentUserId() {
-            try {
-                int processUserId = UserHandle.myUserId();
-                int currentUserId = mActivityManager.getCurrentUser().id;
-                if (processUserId != currentUserId) {
-                    if (DEBUG) {
-                        Log.d(TAG, "UID mismatch. SystemUI is running uid=" + processUserId
-                            + " and the current user is uid=" + currentUserId);
-                    }
-                    return false;
-                }
-            } catch (RemoteException e) {
-                Log.w(TAG, "Unable to get current user.");
-            }
-            return true;
-        }
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 26da551..b22ea4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -1,9 +1,12 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -49,9 +52,14 @@
         while (numPages < getChildCount()) {
             removeViewAt(getChildCount() - 1);
         }
+        TypedArray array = getContext().obtainStyledAttributes(
+                new int[]{android.R.attr.colorForeground});
+        int color = array.getColor(0, 0);
+        array.recycle();
         while (numPages > getChildCount()) {
             ImageView v = new ImageView(mContext);
             v.setImageResource(R.drawable.minor_a_b);
+            v.setImageTintList(ColorStateList.valueOf(color));
             addView(v, new LayoutParams(mPageIndicatorWidth, mPageIndicatorHeight));
         }
         // Refresh state.
@@ -196,7 +204,7 @@
         for (int i = 0; i < N; i++) {
             getChildAt(i).measure(widthChildSpec, heightChildSpec);
         }
-        int width = (mPageIndicatorWidth - mPageDotWidth) * N + mPageDotWidth;
+        int width = (mPageIndicatorWidth - mPageDotWidth) * (N - 1) + mPageDotWidth;
         setMeasuredDimension(width, mPageIndicatorHeight);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 1c242e9..a231e79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -29,7 +29,6 @@
     private PageIndicator mPageIndicator;
 
     private int mNumPages;
-    private View mDecorGroup;
     private PageListener mPageListener;
 
     private int mPosition;
@@ -145,14 +144,14 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
-        mDecorGroup = findViewById(R.id.page_decor);
-        ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
-
-        mPages.add((TilePage) LayoutInflater.from(mContext)
+        mPages.add((TilePage) LayoutInflater.from(getContext())
                 .inflate(R.layout.qs_paged_page, this, false));
     }
 
+    public void setPageIndicator(PageIndicator indicator) {
+        mPageIndicator = indicator;
+    }
+
     @Override
     public int getOffsetTop(TileRecord tile) {
         final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
@@ -196,7 +195,7 @@
                 if (++index == mPages.size()) {
                     if (DEBUG) Log.d(TAG, "Adding page for "
                             + tile.tile.getClass().getSimpleName());
-                    mPages.add((TilePage) LayoutInflater.from(mContext)
+                    mPages.add((TilePage) LayoutInflater.from(getContext())
                             .inflate(R.layout.qs_paged_page, this, false));
                 }
             }
@@ -211,7 +210,7 @@
             }
             if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
             mPageIndicator.setNumPages(mNumPages);
-            mDecorGroup.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
+            mPageIndicator.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
             setAdapter(mAdapter);
             mAdapter.notifyDataSetChanged();
             setCurrentItem(0, false);
@@ -243,8 +242,7 @@
                 maxHeight = height;
             }
         }
-        setMeasuredDimension(getMeasuredWidth(), maxHeight
-                + (mDecorGroup.getVisibility() != View.GONE ? mDecorGroup.getMeasuredHeight() : 0));
+        setMeasuredDimension(getMeasuredWidth(), maxHeight);
     }
 
     private final Runnable mDistribute = new Runnable() {
@@ -265,7 +263,7 @@
         public TilePage(Context context, AttributeSet attrs) {
             super(context, attrs);
             updateResources();
-            setContentDescription(mContext.getString(R.string.accessibility_desc_quick_settings));
+            setContentDescription(getContext().getString(R.string.accessibility_desc_quick_settings));
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fdefcf9..409943d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -194,6 +194,7 @@
                 translationYBuilder.addFloat(label, "translationY", -yDiff, 0);
 
                 mTopFiveQs.add(tileIcon);
+                mTopFiveQs.add(tileView.getBgCicle());
                 mAllViews.add(tileIcon);
                 mAllViews.add(quickTileView);
             } else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -223,9 +224,10 @@
             // Make brightness appear static position and alpha in through second half.
             View brightness = mQsPanel.getBrightnessView();
             if (brightness != null) {
-                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
+//                firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0);
                 mBrightnessAnimator = new TouchAnimator.Builder()
                         .addFloat(brightness, "alpha", 0, 1)
+                        .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
                         .setStartDelay(.5f)
                         .build();
                 mAllViews.add(brightness);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f4da5ec..91b4d0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -18,18 +18,12 @@
 
 import android.content.Context;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS.HeightListener;
 import com.android.systemui.qs.customize.QSCustomizer;
-import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.phone.QSTileHost;
-import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
 
 /**
  * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
@@ -95,7 +89,7 @@
         updateBottom();
     }
 
-    void updateBottom() {
+    public void updateBottom() {
         int height = calculateContainerHeight();
         setBottom(getTop() + height);
         mQSDetail.setBottom(getTop() + height);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 5027144..a20b7ba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -33,11 +33,15 @@
 import android.widget.TextView;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
 import com.android.systemui.plugins.qs.QS.Callback;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
 public class QSDetail extends LinearLayout {
@@ -160,7 +164,8 @@
             setupDetailHeader(adapter);
             if (toggleQs && !mFullyExpanded) {
                 mTriggeredExpand = true;
-                mHost.animateToggleQSExpansion();
+                SysUiServiceProvider.getComponent(mContext, CommandQueue.class)
+                        .animateExpandSettingsPanel(null);
             } else {
                 mTriggeredExpand = false;
             }
@@ -171,7 +176,8 @@
             x = mOpenX;
             y = mOpenY;
             if (toggleQs && mTriggeredExpand) {
-                mHost.animateToggleQSExpansion();
+                SysUiServiceProvider.getComponent(mContext, CommandQueue.class)
+                        .animateCollapsePanels();
                 mTriggeredExpand = false;
             }
         }
@@ -231,12 +237,8 @@
     protected void setupDetailFooter(DetailAdapter adapter) {
         final Intent settingsIntent = adapter.getSettingsIntent();
         mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
-        mDetailSettingsButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mHost.startActivityDismissingKeyguard(settingsIntent);
-            }
-        });
+        mDetailSettingsButton.setOnClickListener(v -> Dependency.get(ActivityStarter.class)
+                .postStartActivityDismissingKeyguard(settingsIntent, 0));
     }
 
     protected void setupDetailHeader(final DetailAdapter adapter) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index fb3b1d9..0bf3f15 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -19,11 +19,9 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.SpannableStringBuilder;
 import android.text.method.LinkMovementMethod;
@@ -33,12 +31,13 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnClickListener;
-import android.view.Window;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.SecurityController;
@@ -55,12 +54,13 @@
     private final ImageView mFooterIcon2;
     private final Context mContext;
     private final Callback mCallback = new Callback();
+    private final SecurityController mSecurityController;
+    private final ActivityStarter mActivityStarter;
+    private final Handler mMainHandler;
 
-    private SecurityController mSecurityController;
     private AlertDialog mDialog;
     private QSTileHost mHost;
     protected Handler mHandler;
-    private final Handler mMainHandler;
 
     private boolean mIsVisible;
     private boolean mIsIconVisible;
@@ -81,13 +81,13 @@
         mFooterIcon2Id = R.drawable.ic_qs_network_logging;
         mContext = context;
         mMainHandler = new Handler(Looper.getMainLooper());
+        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mSecurityController = Dependency.get(SecurityController.class);
+        mHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
     }
 
-    public void setHostEnvironment(QSTileHost host, SecurityController securityController,
-            Looper looper) {
+    public void setHostEnvironment(QSTileHost host) {
         mHost = host;
-        mSecurityController = securityController;
-        mHandler = new H(looper);
     }
 
     public void setListening(boolean listening) {
@@ -173,7 +173,7 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == DialogInterface.BUTTON_NEGATIVE) {
             final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
-            mHost.startActivityDismissingKeyguard(settingsIntent);
+            mActivityStarter.postStartActivityDismissingKeyguard(settingsIntent, 0);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index 9c4a149..f28a0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -16,14 +16,20 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.QSTile.getColorForState;
+
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
+
 import com.android.systemui.R;
 
 import java.util.Objects;
@@ -34,6 +40,8 @@
     protected final int mIconSizePx;
     protected final int mTilePaddingBelowIconPx;
     private boolean mAnimationEnabled = true;
+    private int mState = -1;
+    private int mTint;
 
     public QSIconView(Context context) {
         super(context);
@@ -65,7 +73,6 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int w = getMeasuredWidth();
-        final int h = getMeasuredHeight();
         int top = 0;
         final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
         layout(mIcon, iconLeft, top);
@@ -100,8 +107,43 @@
         } else {
             iv.clearColorFilter();
         }
+        if (state.state != mState) {
+            int color = getColorForState(getContext(), state.state);
+            mState = state.state;
+            if (iv.isShown()) {
+                animateGrayScale(mTint, color, iv);
+                mTint = color;
+            } else {
+                setTint(iv, color);
+                mTint = color;
+            }
+        }
     }
 
+    public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
+        final float fromAlpha = Color.alpha(fromColor);
+        final float toAlpha = Color.alpha(toColor);
+        final float fromChannel = Color.red(fromColor);
+        final float toChannel = Color.red(toColor);
+
+        ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+        anim.setDuration(350);
+
+        anim.addUpdateListener(animation -> {
+            float fraction = animation.getAnimatedFraction();
+            int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
+            int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
+
+            setTint(iv, Color.argb(alpha, channel, channel, channel));
+        });
+        anim.start();
+    }
+
+    public static void setTint(ImageView iv, int color) {
+        iv.setImageTintList(ColorStateList.valueOf(color));
+    }
+
+
     protected int getIconMeasureMode() {
         return MeasureSpec.EXACTLY;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 9feaa0a..e004828 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -54,6 +54,7 @@
     protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
     protected final View mBrightnessView;
     private final H mHandler = new H();
+    private final View mPageIndicator;
 
     private int mPanelPaddingBottom;
     private int mBrightnessPaddingTop;
@@ -84,21 +85,31 @@
 
         setOrientation(VERTICAL);
 
-        mBrightnessView = LayoutInflater.from(context).inflate(
-                R.layout.quick_settings_brightness_dialog, this, false);
-        addView(mBrightnessView);
-
         setupTileLayout();
 
         mFooter = new QSFooter(this, context);
         addView(mFooter.getView());
 
+        mPageIndicator = LayoutInflater.from(context).inflate(
+                R.layout.qs_page_indicator, this, false);
+        addView(mPageIndicator);
+        if (mTileLayout instanceof PagedTileLayout) {
+            ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
+        }
+
         updateResources();
 
+        mBrightnessView = LayoutInflater.from(context).inflate(
+                R.layout.quick_settings_brightness_dialog, this, false);
+        addView(mBrightnessView);
+
         mBrightnessController = new BrightnessController(getContext(),
                 (ImageView) findViewById(R.id.brightness_icon),
                 (ToggleSliderView) findViewById(R.id.brightness_slider));
+    }
 
+    public View getPageIndicator() {
+        return mPageIndicator;
     }
 
     protected void setupTileLayout() {
@@ -179,12 +190,11 @@
         mHost = host;
         mHost.addCallback(this);
         setTiles(mHost.getTiles());
-        mFooter.setHostEnvironment(host, host.getSecurityController(), host.getLooper());
+        mFooter.setHostEnvironment(host);
         mCustomizePanel = customizer;
         if (mCustomizePanel != null) {
             mCustomizePanel.setHost(mHost);
         }
-        mBrightnessController.setBackgroundLooper(host.getLooper());
     }
 
     public QSTileHost getHost() {
@@ -359,20 +369,10 @@
         };
         r.tile.addCallback(callback);
         r.callback = callback;
-        final View.OnClickListener click = new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                onTileClick(r.tile);
-            }
-        };
-        final View.OnLongClickListener longClick = new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                r.tile.longClick();
-                return true;
-            }
-        };
-        r.tileView.init(click, longClick);
+        r.tileView.init(v -> r.tile.click(), v -> r.tile.secondaryClick(), v -> {
+            r.tile.longClick();
+            return true;
+        });
         r.tile.refreshState();
         mRecords.add(r);
 
@@ -402,10 +402,6 @@
         });
     }
 
-    protected void onTileClick(QSTile<?> tile) {
-        tile.click();
-    }
-
     public void closeDetail() {
         if (mCustomizePanel != null && mCustomizePanel.isShown()) {
             // Treat this as a detail panel for now, to make things easy.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index f73241c..e18654e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -17,13 +17,13 @@
 package com.android.systemui.qs;
 
 import android.app.ActivityManager;
-import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.service.quicksettings.Tile;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -31,29 +31,22 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.Dependency;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.qs.external.TileServices;
-import com.android.systemui.statusbar.phone.ManagedProfileController;
-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.RotationLockController;
-import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
 
+import com.android.settingslib.Utils;
+
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
+import com.android.systemui.R;
+
 /**
  * Base quick-settings tile, extend this to create a new tile.
  *
@@ -79,7 +72,9 @@
     private String mTileSpec;
 
     public abstract TState newTileState();
+
     abstract protected void handleClick();
+
     abstract protected void handleUpdateState(TState state, Object arg);
 
     /**
@@ -93,7 +88,7 @@
     protected QSTile(Host host) {
         mHost = host;
         mContext = host.getContext();
-        mHandler = new H(host.getLooper());
+        mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
     }
 
     /**
@@ -134,7 +129,9 @@
         return null; // optional
     }
 
-    protected DetailAdapter createDetailAdapter() { throw new UnsupportedOperationException(); }
+    protected DetailAdapter createDetailAdapter() {
+        throw new UnsupportedOperationException();
+    }
 
     /**
      * Is a startup check whether this device currently supports this tile.
@@ -233,7 +230,8 @@
 
     protected void handleLongClick() {
         MetricsLogger.action(mContext, MetricsEvent.ACTION_QS_LONG_PRESS, getTileSpec());
-        mHost.startActivityDismissingKeyguard(getLongClickIntent());
+        Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
+                getLongClickIntent(), 0);
     }
 
     public abstract Intent getLongClickIntent();
@@ -319,6 +317,21 @@
 
     public abstract CharSequence getTileLabel();
 
+    public static int getColorForState(Context context, int state) {
+        switch (state) {
+            case Tile.STATE_UNAVAILABLE:
+                return Utils.getDisabled(context,
+                        Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+            case Tile.STATE_INACTIVE:
+                return Utils.getColorAttr(context, android.R.attr.textColorSecondary);
+            case Tile.STATE_ACTIVE:
+                return Utils.getColorAttr(context, android.R.attr.colorPrimary);
+            default:
+                Log.e("QSTile", "Invalid state " + state);
+                return 0;
+        }
+    }
+
     protected final class H extends Handler {
         private static final int ADD_CALLBACK = 1;
         private static final int CLICK = 2;
@@ -357,7 +370,8 @@
                     if (mState.disabledByPolicy) {
                         Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
                                 mContext, mState.enforcedAdmin);
-                        mHost.startActivityDismissingKeyguard(intent);
+                        Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
+                                intent, 0);
                     } else {
                         mAnnounceNextStateChange = true;
                         handleClick();
@@ -412,36 +426,17 @@
     }
 
     public interface Host {
-        void startActivityDismissingKeyguard(Intent intent);
-        void startActivityDismissingKeyguard(PendingIntent intent);
-        void startRunnableDismissingKeyguard(Runnable runnable);
         void warn(String message, Throwable t);
         void collapsePanels();
-        void animateToggleQSExpansion();
         void openPanels();
-        Looper getLooper();
         Context getContext();
         Collection<QSTile<?>> getTiles();
         void addCallback(Callback callback);
         void removeCallback(Callback callback);
-        BluetoothController getBluetoothController();
-        LocationController getLocationController();
-        RotationLockController getRotationLockController();
-        NetworkController getNetworkController();
-        ZenModeController getZenModeController();
-        HotspotController getHotspotController();
-        CastController getCastController();
-        FlashlightController getFlashlightController();
-        KeyguardMonitor getKeyguardMonitor();
-        UserSwitcherController getUserSwitcherController();
-        UserInfoController getUserInfoController();
-        BatteryController getBatteryController();
         TileServices getTileServices();
         void removeTile(String tileSpec);
-        ManagedProfileController getManagedProfileController();
 
-
-        public interface Callback {
+        interface Callback {
             void onTilesChanged();
         }
     }
@@ -546,6 +541,7 @@
 
     public static class State {
         public Icon icon;
+        public int state = Tile.STATE_ACTIVE;
         public CharSequence label;
         public CharSequence contentDescription;
         public CharSequence dualLabelContentDescription;
@@ -572,6 +568,7 @@
                     || !Objects.equals(other.expandedAccessibilityClassName,
                     expandedAccessibilityClassName)
                     || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
+                    || !Objects.equals(other.state, state)
                     || !Objects.equals(other.enforcedAdmin, enforcedAdmin);
             other.icon = icon;
             other.label = label;
@@ -582,6 +579,7 @@
             other.expandedAccessibilityClassName = expandedAccessibilityClassName;
             other.autoMirrorDrawable = autoMirrorDrawable;
             other.disabledByPolicy = disabledByPolicy;
+            other.state = state;
             if (enforcedAdmin == null) {
                 other.enforcedAdmin = null;
             } else if (other.enforcedAdmin == null) {
@@ -609,6 +607,7 @@
             sb.append(",autoMirrorDrawable=").append(autoMirrorDrawable);
             sb.append(",disabledByPolicy=").append(disabledByPolicy);
             sb.append(",enforcedAdmin=").append(enforcedAdmin);
+            sb.append(",state=").append(state);
             return sb.append(']');
         }
     }
@@ -648,7 +647,6 @@
         public boolean connected;
         public boolean activityIn;
         public boolean activityOut;
-        public int overlayIconId;
         public boolean filter;
         public boolean isOverlayIconWide;
 
@@ -657,12 +655,10 @@
             final SignalState o = (SignalState) other;
             final boolean changed = o.connected != connected || o.activityIn != activityIn
                     || o.activityOut != activityOut
-                    || o.overlayIconId != overlayIconId
                     || o.isOverlayIconWide != isOverlayIconWide;
             o.connected = connected;
             o.activityIn = activityIn;
             o.activityOut = activityOut;
-            o.overlayIconId = overlayIconId;
             o.filter = filter;
             o.isOverlayIconWide = isOverlayIconWide;
             return super.copyTo(other) || changed;
@@ -674,7 +670,6 @@
             rt.insert(rt.length() - 1, ",connected=" + connected);
             rt.insert(rt.length() - 1, ",activityIn=" + activityIn);
             rt.insert(rt.length() - 1, ",activityOut=" + activityOut);
-            rt.insert(rt.length() - 1, ",overlayIconId=" + overlayIconId);
             rt.insert(rt.length() - 1, ",filter=" + filter);
             rt.insert(rt.length() - 1, ",wideOverlayIcon=" + isOverlayIconWide);
             return rt;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
index 2b7fcc5..a177cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -15,31 +15,49 @@
  */
 package com.android.systemui.qs;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.service.quicksettings.Tile;
 import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
 import android.widget.LinearLayout;
 import android.widget.Switch;
 
+import com.android.settingslib.Utils;
+
 import com.android.systemui.R;
 
 public class QSTileBaseView extends LinearLayout {
 
+    private static final String TAG = "QSTileBaseView";
     private final H mHandler = new H();
+    private final ImageView mBg;
     protected QSIconView mIcon;
     protected RippleDrawable mRipple;
     private Drawable mTileBackground;
     private String mAccessibilityClass;
     private boolean mTileState;
     private boolean mCollapsedView;
+    private final int mColorActive;
+    private final int mColorInactive;
+    private final int mColorDisabled;
+    private int mCircleColor;
 
     public QSTileBaseView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -47,8 +65,26 @@
 
     public QSTileBaseView(Context context, QSIconView icon, boolean collapsedView) {
         super(context);
+        // Default to Quick Tile padding, and QSTileView will specify its own padding.
+        int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
+
+        FrameLayout frame = new FrameLayout(context);
+        frame.setForegroundGravity(Gravity.CENTER);
+        int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+        addView(frame, new LayoutParams(size, size));
+        mBg = new ImageView(getContext());
+        mBg.setScaleType(ScaleType.FIT_CENTER);
+        mBg.setImageResource(R.drawable.ic_qs_circle);
+        frame.addView(mBg);
         mIcon = icon;
-        addView(mIcon);
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        params.setMargins(0, padding, 0, padding);
+        frame.addView(mIcon, params);
+        mColorActive = Utils.getColorAttr(context, android.R.attr.textColorPrimary);
+        mColorDisabled = Utils.getDisabled(context,
+                Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+        mColorInactive = Utils.getColorAttr(context, android.R.attr.textColorSecondary);
 
         mTileBackground = newTileBackground();
         if (mTileBackground instanceof RippleDrawable) {
@@ -57,18 +93,20 @@
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
         setBackground(mTileBackground);
 
-        // Default to Quick Tile padding, and QSTileView will specify its own padding.
-        int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
-        setPadding(0, padding, 0, padding);
+        setPadding(0, 0, 0, 0);
         setClipChildren(false);
         setClipToPadding(false);
         mCollapsedView = collapsedView;
         setFocusable(true);
     }
 
+    public View getBgCicle() {
+        return mBg;
+    }
+
     protected Drawable newTileBackground() {
-        final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
-        final TypedArray ta = mContext.obtainStyledAttributes(attrs);
+        final int[] attrs = new int[]{android.R.attr.selectableItemBackgroundBorderless};
+        final TypedArray ta = getContext().obtainStyledAttributes(attrs);
         final Drawable d = ta.getDrawable(0);
         ta.recycle();
         return d;
@@ -85,11 +123,12 @@
         // center the touch feedback on the center of the icon, and dial it down a bit
         final int cx = width / 2;
         final int cy = height / 2;
-        final int rad = (int)(mIcon.getHeight() * .85f);
+        final int rad = (int) (mIcon.getHeight() * .85f);
         mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
     }
 
-    public void init(OnClickListener click, OnLongClickListener longClick) {
+    public void init(OnClickListener click, OnClickListener secondaryClick,
+            OnLongClickListener longClick) {
         setClickable(true);
         setOnClickListener(click);
         setOnLongClickListener(longClick);
@@ -128,6 +167,16 @@
     }
 
     protected void handleStateChanged(QSTile.State state) {
+        int circleColor = getCircleColor(state.state);
+        if (circleColor != mCircleColor) {
+            if (mBg.isShown()) {
+                QSIconView.animateGrayScale(mCircleColor, circleColor, mBg);
+            } else {
+                QSIconView.setTint(mBg, circleColor);
+            }
+            mCircleColor = circleColor;
+        }
+
         mIcon.setIcon(state);
         if (mCollapsedView && !TextUtils.isEmpty(state.minimalContentDescription)) {
             setContentDescription(state.minimalContentDescription);
@@ -144,6 +193,19 @@
         }
     }
 
+    private int getCircleColor(int state) {
+        switch (state) {
+            case Tile.STATE_ACTIVE:
+                return mColorActive;
+            case Tile.STATE_INACTIVE:
+            case Tile.STATE_UNAVAILABLE:
+                return mColorDisabled;
+            default:
+                Log.e(TAG, "Invalid state " + state);
+                return 0;
+        }
+    }
+
     public QSIconView getIcon() {
         return mIcon;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index e59873a..7126f3c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -16,27 +16,34 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.qs.QSTile.getColorForState;
+
 import android.content.Context;
 import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.util.MathUtils;
+import android.service.quicksettings.Tile;
+import android.text.SpannableStringBuilder;
+import android.text.style.ForegroundColorSpan;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+
 import libcore.util.Objects;
 
 /** View that represents a standard quick settings tile. **/
 public class QSTileView extends QSTileBaseView {
-    private final int mTileSpacingPx;
-    private int mTilePaddingTopPx;
 
     protected TextView mLabel;
     private ImageView mPadLock;
+    private int mState;
+    private OnClickListener mClick;
+    private OnClickListener mSecondaryClick;
 
     public QSTileView(Context context, QSIconView icon) {
         this(context, icon, false);
@@ -45,13 +52,10 @@
     public QSTileView(Context context, QSIconView icon, boolean collapsedView) {
         super(context, icon, collapsedView);
 
-        final Resources res = context.getResources();
-        mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
-
         setClipChildren(false);
+        setClipToPadding(false);
 
         setClickable(true);
-        updateTopPadding();
         setId(View.generateViewId());
         createLabel();
         setOrientation(VERTICAL);
@@ -62,27 +66,17 @@
         return mLabel;
     }
 
-    protected void updateTopPadding() {
-        Resources res = getResources();
-        int padding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
-        int largePadding = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top_large_text);
-        float largeFactor = (MathUtils.constrain(getResources().getConfiguration().fontScale,
-                1.0f, FontSizeUtils.LARGE_TEXT_SCALE) - 1f) / (FontSizeUtils.LARGE_TEXT_SCALE - 1f);
-        mTilePaddingTopPx = Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
-        setPadding(mTileSpacingPx, mTilePaddingTopPx + mTileSpacingPx, mTileSpacingPx,
-                mTileSpacingPx);
-        requestLayout();
-    }
-
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        updateTopPadding();
         FontSizeUtils.updateFontSize(mLabel, R.dimen.qs_tile_text_size);
     }
 
     protected void createLabel() {
-        View view = LayoutInflater.from(mContext).inflate(R.layout.qs_tile_label, null);
+        ViewGroup view = (ViewGroup) LayoutInflater.from(getContext())
+                .inflate(R.layout.qs_tile_label, null);
+        view.setClipChildren(false);
+        view.setClipToPadding(false);
         mLabel = (TextView) view.findViewById(R.id.tile_label);
         mPadLock = (ImageView) view.findViewById(R.id.restricted_padlock);
         addView(view);
@@ -91,10 +85,32 @@
     @Override
     protected void handleStateChanged(QSTile.State state) {
         super.handleStateChanged(state);
-        if (!Objects.equal(mLabel.getText(), state.label)) {
+        if (!Objects.equal(mLabel.getText(), state.label) || mState != state.state) {
+            if (state.state == Tile.STATE_UNAVAILABLE) {
+                int color = getColorForState(getContext(), state.state);
+                state.label = new SpannableStringBuilder().append(state.label,
+                        new ForegroundColorSpan(color),
+                        SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
+            }
+            mState = state.state;
             mLabel.setText(state.label);
         }
         mLabel.setEnabled(!state.disabledByPolicy);
         mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
     }
+
+    @Override
+    public void init(OnClickListener click, OnClickListener secondaryClick, OnLongClickListener longClick) {
+        mClick = click;
+        mSecondaryClick = secondaryClick;
+        super.init(click, secondaryClick, longClick);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_UP)  {
+            setOnClickListener(event.getY() < (getMeasuredHeight() / 2) ? mClick : mSecondaryClick);
+        }
+        return super.onTouchEvent(event);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index de3e19c..16b351e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -56,7 +56,7 @@
         }
         mTileLayout = new HeaderTileLayout(context);
         mTileLayout.setListening(mListening);
-        addView((View) mTileLayout, 1 /* Between brightness and footer */);
+        addView((View) mTileLayout, 0 /* Between brightness and footer */);
     }
 
     @Override
@@ -113,11 +113,6 @@
     }
 
     @Override
-    protected void onTileClick(QSTile<?> tile) {
-        tile.secondaryClick();
-    }
-
-    @Override
     public void onTuningChanged(String key, String newValue) {
         // No tunings for you.
         if (key.equals(QS_SHOW_BRIGHTNESS)) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index b2bfa06..8555e31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -33,7 +33,6 @@
 
     private FrameLayout mIconFrame;
     private ImageView mSignal;
-    private ImageView mOverlay;
     private ImageView mIn;
     private ImageView mOut;
 
@@ -62,8 +61,6 @@
         mIconFrame = new FrameLayout(mContext);
         mSignal = new ImageView(mContext);
         mIconFrame.addView(mSignal);
-        mOverlay = new ImageView(mContext);
-        mIconFrame.addView(mOverlay, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         return mIconFrame;
     }
 
@@ -109,17 +106,6 @@
     public void setIcon(QSTile.State state) {
         final SignalState s = (SignalState) state;
         setIcon(mSignal, s);
-        if (s.overlayIconId > 0) {
-            mOverlay.setVisibility(VISIBLE);
-            mOverlay.setImageResource(s.overlayIconId);
-        } else {
-            mOverlay.setVisibility(GONE);
-        }
-        if (s.overlayIconId > 0 && s.isOverlayIconWide) {
-            mSignal.setPaddingRelative(mWideOverlayIconStartPadding, 0, 0, 0);
-        } else {
-            mSignal.setPaddingRelative(0, 0, 0, 0);
-        }
         Drawable drawable = mSignal.getDrawable();
         if (state.autoMirrorDrawable && drawable != null) {
             drawable.setAutoMirrored(true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 0be53b4..730b55d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -36,13 +36,14 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSDetailClipper;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback;
 
 import java.util.ArrayList;
@@ -140,7 +141,7 @@
             mNotifQsContainer.setCustomizerShowing(true);
             announceForAccessibility(mContext.getString(
                     R.string.accessibility_desc_quick_settings_edit));
-            mHost.getKeyguardMonitor().addCallback(mKeyguardCallback);
+            Dependency.get(KeyguardMonitor.class).addCallback(mKeyguardCallback);
         }
     }
 
@@ -156,7 +157,7 @@
             mNotifQsContainer.setCustomizerShowing(false);
             announceForAccessibility(mContext.getString(
                     R.string.accessibility_desc_quick_settings));
-            mHost.getKeyguardMonitor().removeCallback(mKeyguardCallback);
+            Dependency.get(KeyguardMonitor.class).removeCallback(mKeyguardCallback);
         }
     }
 
@@ -206,12 +207,9 @@
         mTileAdapter.saveSpecs(mHost);
     }
 
-    private final Callback mKeyguardCallback = new Callback() {
-        @Override
-        public void onKeyguardChanged() {
-            if (mHost.getKeyguardMonitor().isShowing()) {
-                hide(0, 0);
-            }
+    private final Callback mKeyguardCallback = () -> {
+        if (Dependency.get(KeyguardMonitor.class).isShowing()) {
+            hide(0, 0);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 0cd6490..72e6fcc0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -30,6 +30,7 @@
 import android.service.quicksettings.TileService;
 import android.widget.Button;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DrawableIcon;
@@ -59,7 +60,7 @@
     private void addSystemTiles(final QSTileHost host) {
         String possible = mContext.getString(R.string.quick_settings_tiles_stock);
         String[] possibleTiles = possible.split(",");
-        final Handler qsHandler = new Handler(host.getLooper());
+        final Handler qsHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
         final Handler mainHandler = new Handler(Looper.getMainLooper());
         for (int i = 0; i < possibleTiles.length; i++) {
             final String spec = possibleTiles[i];
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 9e3889b..3afbc35 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -15,15 +15,10 @@
  */
 package com.android.systemui.qs.external;
 
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-
 import android.app.ActivityManager;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
@@ -39,14 +34,21 @@
 import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 import android.view.IWindowManager;
+import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.Dependency;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import libcore.util.Objects;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+
 public class CustomTile extends QSTile<QSTile.State> implements TileChangeListener {
     public static final String PREFIX = "custom(";
 
@@ -63,7 +65,6 @@
     private final IQSTileService mService;
     private final TileServiceManager mServiceManager;
     private final int mUser;
-    private Context mAppContext;
     private android.graphics.drawable.Icon mDefaultIcon;
 
     private boolean mListening;
@@ -81,10 +82,6 @@
         mService = mServiceManager.getTileService();
         mServiceManager.setTileChangeListener(this);
         mUser = ActivityManager.getCurrentUser();
-        try {
-            mAppContext = mContext.createPackageContext(mComponent.getPackageName(), 0);
-        } catch (NameNotFoundException e) {
-        }
     }
 
     private void setTileIcon() {
@@ -287,27 +284,17 @@
         if (mServiceManager.hasPendingBind()) {
             tileState = Tile.STATE_UNAVAILABLE;
         }
+        state.state = tileState;
         Drawable drawable;
-        boolean mHasRes = false;
-        android.graphics.drawable.Icon icon = mTile.getIcon();
         try {
-            drawable = icon.loadDrawable(mAppContext);
-            mHasRes = icon.getType() == android.graphics.drawable.Icon.TYPE_RESOURCE;
+            drawable = mTile.getIcon().loadDrawable(mContext);
         } catch (Exception e) {
             Log.w(TAG, "Invalid icon, forcing into unavailable state");
             tileState = Tile.STATE_UNAVAILABLE;
-            drawable = mDefaultIcon.loadDrawable(mAppContext);
+            drawable = mDefaultIcon.loadDrawable(mContext);
         }
-        final int color = TileColorPicker.getInstance(mContext).getColor(tileState);
-        drawable.setTint(color);
-        state.icon = mHasRes ? new DrawableIconWithRes(drawable, icon.getResId())
-                : new DrawableIcon(drawable);
+        state.icon = new DrawableIcon(drawable);
         state.label = mTile.getLabel();
-        if (tileState == Tile.STATE_UNAVAILABLE) {
-            state.label = new SpannableStringBuilder().append(state.label,
-                    new ForegroundColorSpan(color),
-                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
-        }
         if (mTile.getContentDescription() != null) {
             state.contentDescription = mTile.getContentDescription();
         } else {
@@ -321,13 +308,10 @@
     }
 
     public void startUnlockAndRun() {
-        mHost.startRunnableDismissingKeyguard(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mService.onUnlockComplete();
-                } catch (RemoteException e) {
-                }
+        Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+            try {
+                mService.onUnlockComplete();
+            } catch (RemoteException e) {
             }
         });
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 015a4c0..5c23eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -30,13 +30,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.quicksettings.IQSService;
-import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -284,13 +284,13 @@
 
     @Override
     public boolean isLocked() {
-        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+        KeyguardMonitor keyguardMonitor = Dependency.get(KeyguardMonitor.class);
         return keyguardMonitor.isShowing();
     }
 
     @Override
     public boolean isSecure() {
-        KeyguardMonitor keyguardMonitor = mHost.getKeyguardMonitor();
+        KeyguardMonitor keyguardMonitor = Dependency.get(KeyguardMonitor.class);
         return keyguardMonitor.isSecure() && keyguardMonitor.isShowing();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index e57cd58..e8f90ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -23,6 +23,7 @@
 import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -92,6 +93,7 @@
         } else {
             state.icon = mDisable;
         }
+        state.state = airplaneMode ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.contentDescription = state.label;
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
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 833375e..7e04b67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -19,10 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
-import android.os.Handler;
 import android.service.quicksettings.Tile;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
@@ -41,11 +38,12 @@
 import com.android.settingslib.BatteryInfo;
 import com.android.settingslib.graph.UsageView;
 import com.android.systemui.BatteryMeterDrawable;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.policy.BatteryController;
 
 import java.text.NumberFormat;
@@ -63,7 +61,7 @@
 
     public BatteryTile(Host host) {
         super(host);
-        mBatteryController = host.getBatteryController();
+        mBatteryController = Dependency.get(BatteryController.class);
     }
 
     @Override
@@ -105,6 +103,11 @@
 
     @Override
     protected void handleClick() {
+        mBatteryController.setPowerSaveMode(!mPowerSave);
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
         showDetail(true);
     }
 
@@ -118,26 +121,10 @@
         int level = (arg != null) ? (Integer) arg : mLevel;
         String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
 
-        state.icon = new Icon() {
-            @Override
-            public Drawable getDrawable(Context context) {
-                BatteryMeterDrawable drawable =
-                        new BatteryMeterDrawable(context,
-                        context.getColor(R.color.batterymeter_frame_color));
-                drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
-                drawable.onPowerSaveChanged(mPowerSave);
-                final int color = TileColorPicker.getInstance(context).getColor(Tile.STATE_ACTIVE);
-                drawable.setColorFilter(new PorterDuffColorFilter(color, Mode.SRC_IN));
-                return drawable;
-            }
-
-            @Override
-            public int getPadding() {
-                return mHost.getContext().getResources().getDimensionPixelSize(
-                        R.dimen.qs_battery_padding);
-            }
-        };
-        state.label = percentage;
+        state.state = mCharging ? Tile.STATE_UNAVAILABLE
+                : mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver);
+        state.label = mContext.getString(R.string.battery_detail_switch_title);
         state.contentDescription = mContext.getString(R.string.accessibility_quick_settings_battery,
                 percentage) + "," +
                 (mPowerSave ? mContext.getString(R.string.battery_saver_notification_title)
@@ -153,7 +140,7 @@
         mLevel = level;
         mPluggedIn = pluggedIn;
         mCharging = charging;
-        refreshState((Integer) level);
+        refreshState(level);
         if (mDetailShown) {
             mBatteryDetail.postBindView();
         }
@@ -213,11 +200,6 @@
             mDrawable.onBatteryLevelChanged(100, false, false);
             mDrawable.onPowerSaveChanged(true);
             mDrawable.disableShowPercent();
-
-            final int color = TileColorPicker.getInstance(mCurrentView.getContext())
-                    .getColor(Tile.STATE_ACTIVE);
-            mDrawable.setColorFilter(new PorterDuffColorFilter(color, Mode.SRC_IN));
-
             ((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
             Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
             checkbox.setChecked(mPowerSave);
@@ -293,7 +275,7 @@
                 mDetailShown = true;
                 v.getContext().registerReceiver(mReceiver,
                         new IntentFilter(Intent.ACTION_TIME_TICK), null,
-                        PhoneStatusBar.getTimeTickHandler(v.getContext()));
+                        Dependency.get(Dependency.TIME_TICK_HANDLER));
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index f83b279..91e76ca 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.view.View;
 import android.view.ViewGroup;
@@ -31,7 +32,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
@@ -47,10 +50,12 @@
 
     private final BluetoothController mController;
     private final BluetoothDetailAdapter mDetailAdapter;
+    private final ActivityStarter mActivityStarter;
 
     public BluetoothTile(Host host) {
         super(host);
-        mController = host.getBluetoothController();
+        mController = Dependency.get(BluetoothController.class);
+        mActivityStarter = Dependency.get(ActivityStarter.class);
         mDetailAdapter = (BluetoothDetailAdapter) createDetailAdapter();
     }
 
@@ -74,7 +79,7 @@
     }
 
     @Override
-    protected void handleSecondaryClick() {
+    protected void handleClick() {
         // Secondary clicks are header clicks, just toggle.
         final boolean isEnabled = (Boolean)mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
@@ -87,9 +92,10 @@
     }
 
     @Override
-    protected void handleClick() {
+    protected void handleSecondaryClick() {
         if (!mController.canConfigBluetooth()) {
-            mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
+            mActivityStarter.postStartActivityDismissingKeyguard(
+                    new Intent(Settings.ACTION_BLUETOOTH_SETTINGS), 0);
             return;
         }
         showDetail(true);
@@ -140,11 +146,13 @@
             if (TextUtils.isEmpty(state.label)) {
                 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
             }
+            state.state = Tile.STATE_ACTIVE;
         } else {
             state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
             state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_bluetooth_off);
+            state.state = Tile.STATE_INACTIVE;
         }
 
         CharSequence bluetoothName = state.label;
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 8afa91e..7415765 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
@@ -27,7 +28,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
@@ -48,12 +51,14 @@
     private final CastDetailAdapter mDetailAdapter;
     private final KeyguardMonitor mKeyguard;
     private final Callback mCallback = new Callback();
+    private final ActivityStarter mActivityStarter;
 
     public CastTile(Host host) {
         super(host);
-        mController = host.getCastController();
+        mController = Dependency.get(CastController.class);
         mDetailAdapter = new CastDetailAdapter();
-        mKeyguard = host.getKeyguardMonitor();
+        mKeyguard = Dependency.get(KeyguardMonitor.class);
+        mActivityStarter = Dependency.get(ActivityStarter.class);
     }
 
     @Override
@@ -93,15 +98,17 @@
     }
 
     @Override
+    protected void handleSecondaryClick() {
+        handleClick();
+    }
+
+    @Override
     protected void handleClick() {
         if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
-            mHost.startRunnableDismissingKeyguard(new Runnable() {
-                @Override
-                public void run() {
-                    MetricsLogger.action(mContext, getMetricsCategory());
-                    showDetail(true);
-                    mHost.openPanels();
-                }
+            mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
+                MetricsLogger.action(mContext, getMetricsCategory());
+                showDetail(true);
+                mHost.openPanels();
             });
             return;
         }
@@ -135,6 +142,7 @@
         if (!state.value && connecting) {
             state.label = mContext.getString(R.string.quick_settings_connecting);
         }
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
                 : R.drawable.ic_qs_cast_off);
         mDetailAdapter.updateItems(devices);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 1406c9f..75c4a75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.service.quicksettings.Tile;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -28,7 +29,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSIconView;
 import com.android.systemui.qs.QSTile;
@@ -47,10 +50,12 @@
     private final CellularDetailAdapter mDetailAdapter;
 
     private final CellSignalCallback mSignalCallback = new CellSignalCallback();
+    private final ActivityStarter mActivityStarter;
 
     public CellularTile(Host host) {
         super(host);
-        mController = host.getNetworkController();
+        mController = Dependency.get(NetworkController.class);
+        mActivityStarter = Dependency.get(ActivityStarter.class);
         mDataController = mController.getMobileDataController();
         mDetailAdapter = new CellularDetailAdapter();
     }
@@ -86,11 +91,16 @@
 
     @Override
     protected void handleClick() {
+        mDataController.setMobileDataEnabled(!mDataController.isMobileDataEnabled());
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
         MetricsLogger.action(mContext, getMetricsCategory());
         if (mDataController.isMobileDataSupported()) {
             showDetail(true);
         } else {
-            mHost.startActivityDismissingKeyguard(CELLULAR_SETTINGS);
+            mActivityStarter.postStartActivityDismissingKeyguard(CELLULAR_SETTINGS, 0);
         }
     }
 
@@ -111,10 +121,13 @@
                 : !cb.enabled || cb.airplaneModeEnabled ? R.drawable.ic_qs_signal_disabled
                 : cb.mobileSignalIconId > 0 ? cb.mobileSignalIconId
                 : R.drawable.ic_qs_signal_no_signal;
-        state.icon = ResourceIcon.get(iconId);
+        if (cb.dataTypeIconId != 0) {
+            state.icon = ResourceIcon.get(cb.dataTypeIconId);
+        } else {
+            state.icon = ResourceIcon.get(iconId);
+        }
         state.isOverlayIconWide = cb.isDataTypeIconWide;
         state.autoMirrorDrawable = !cb.noSim;
-        state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) ? cb.dataTypeIconId : 0;
         state.filter = iconId != R.drawable.ic_qs_no_sim;
         state.activityIn = cb.enabled && cb.activityIn;
         state.activityOut = cb.enabled && cb.activityOut;
@@ -148,6 +161,7 @@
                 = Button.class.getName();
         state.value = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 77f063d..0a8afb0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -19,6 +19,7 @@
 import android.content.Intent;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
@@ -95,6 +96,7 @@
         final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
         final boolean enabled = value != 0;
         state.value = enabled;
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
         state.icon = enabled ? mEnable : mDisable;
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 65432dc..412fe3d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -16,15 +16,18 @@
 
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.DataSaverController;
+import com.android.systemui.statusbar.policy.NetworkController;
 
 public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
         DataSaverController.Listener{
@@ -33,7 +36,7 @@
 
     public DataSaverTile(Host host) {
         super(host);
-        mDataSaverController = host.getNetworkController().getDataSaverController();
+        mDataSaverController = Dependency.get(NetworkController.class).getDataSaverController();
     }
 
     @Override
@@ -96,6 +99,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.value = arg instanceof Boolean ? (Boolean) arg
                 : mDataSaverController.isDataSaverEnabled();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.data_saver);
         state.contentDescription = state.label;
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_data_saver
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 198375d..3c1f504 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -25,6 +25,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.quicksettings.Tile;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
@@ -34,9 +35,11 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -73,7 +76,7 @@
 
     public DndTile(Host host) {
         super(host);
-        mController = host.getZenModeController();
+        mController = Dependency.get(ZenModeController.class);
         mDetailAdapter = new DndDetailAdapter();
         mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
         mReceiverRegistered = true;
@@ -121,7 +124,17 @@
     }
 
     @Override
-    public void handleClick() {
+    protected void handleClick() {
+        if (mState.value) {
+            mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
+        } else {
+            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
+            mController.setZen(zen, null, TAG);
+        }
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
         if (mController.isVolumeRestricted()) {
             // Collapse the panels, so the user can see the toast.
             mHost.collapsePanels();
@@ -131,13 +144,9 @@
             return;
         }
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
-        if (mState.value) {
-            mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
-        } else {
-            showDetail(true);
-            int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
-            mController.setZen(zen, null, TAG);
-        }
+        showDetail(true);
+        int zen = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN, Global.ZEN_MODE_ALARMS);
+        mController.setZen(zen, null, TAG);
     }
 
     @Override
@@ -151,6 +160,7 @@
         final boolean newValue = zen != Global.ZEN_MODE_OFF;
         final boolean valueChanged = state.value != newValue;
         state.value = newValue;
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
@@ -305,7 +315,8 @@
     private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() {
         @Override
         public void onPrioritySettings() {
-            mHost.startActivityDismissingKeyguard(ZEN_PRIORITY_SETTINGS);
+            Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(
+                    ZEN_PRIORITY_SETTINGS, 0);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 416c7ce..ac82753 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -27,9 +27,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.policy.FlashlightController;
 
 /** Quick settings tile: Control flashlight **/
@@ -46,7 +46,7 @@
 
     public FlashlightTile(Host host) {
         super(host);
-        mFlashlightController = host.getFlashlightController();
+        mFlashlightController = Dependency.get(FlashlightController.class);
     }
 
     @Override
@@ -107,17 +107,12 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
         if (!mFlashlightController.isAvailable()) {
-            Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_disable)
+            Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_enable)
                     .mutate();
-            final int disabledColor = TileColorPicker.getInstance(mContext)
-                    .getColor(Tile.STATE_UNAVAILABLE);
-            icon.setTint(disabledColor);
             state.icon = new DrawableIcon(icon);
-            state.label = new SpannableStringBuilder().append(state.label,
-                    new ForegroundColorSpan(disabledColor),
-                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_flashlight_unavailable);
+            state.state = Tile.STATE_UNAVAILABLE;
             return;
         }
         if (arg instanceof Boolean) {
@@ -134,6 +129,7 @@
         state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label);
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 99485bb..70f8109 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -29,10 +29,10 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.external.TileColorPicker;
 import com.android.systemui.statusbar.policy.HotspotController;
 
 /** Quick settings tile: Hotspot **/
@@ -53,7 +53,7 @@
 
     public HotspotTile(Host host) {
         super(host);
-        mController = host.getHotspotController();
+        mController = Dependency.get(HotspotController.class);
         mAirplaneMode = new GlobalSetting(mContext, mHandler, Global.AIRPLANE_MODE_ON) {
             @Override
             protected void handleValueChanged(int value) {
@@ -126,11 +126,6 @@
         boolean wasAirplane = state.isAirplaneMode;
         state.isAirplaneMode = mAirplaneMode.getValue() != 0;
         if (state.isAirplaneMode) {
-            final int disabledColor = TileColorPicker.getInstance(mContext)
-                    .getColor(Tile.STATE_UNAVAILABLE);
-            state.label = new SpannableStringBuilder().append(state.label,
-                    new ForegroundColorSpan(disabledColor),
-                    SpannableStringBuilder.SPAN_INCLUSIVE_INCLUSIVE);
             state.icon = mUnavailable;
         } else if (wasAirplane) {
             state.icon = mDisableNoAnimation;
@@ -138,6 +133,8 @@
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
         state.contentDescription = state.label;
+        state.state = state.isAirplaneMode ? Tile.STATE_UNAVAILABLE
+                : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index f968816..fcc9596 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -31,6 +31,8 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.qs.QSTile;
 
 import java.util.Arrays;
@@ -105,7 +107,7 @@
         try {
             if (pi != null) {
                 if (pi.isActivity()) {
-                    getHost().startActivityDismissingKeyguard(pi);
+                    Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(pi);
                 } else {
                     pi.send();
                 }
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 8a9a696..5374f18 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -18,13 +18,15 @@
 
 import android.content.Intent;
 import android.os.UserManager;
-
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -46,8 +48,8 @@
 
     public LocationTile(Host host) {
         super(host);
-        mController = host.getLocationController();
-        mKeyguard = host.getKeyguardMonitor();
+        mController = Dependency.get(LocationController.class);
+        mKeyguard = Dependency.get(KeyguardMonitor.class);
     }
 
     @Override
@@ -74,18 +76,15 @@
     @Override
     protected void handleClick() {
         if (mKeyguard.isSecure() && mKeyguard.isShowing()) {
-            mHost.startRunnableDismissingKeyguard(new Runnable() {
-                @Override
-                public void run() {
-                    final boolean wasEnabled = (Boolean) mState.value;
-                    mHost.openPanels();
-                    MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
-                    mController.setLocationEnabled(!wasEnabled);
-                }
+            Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+                final boolean wasEnabled = mState.value;
+                mHost.openPanels();
+                MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
+                mController.setLocationEnabled(!wasEnabled);
             });
             return;
         }
-        final boolean wasEnabled = (Boolean) mState.value;
+        final boolean wasEnabled = mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
         mController.setLocationEnabled(!wasEnabled);
     }
@@ -115,6 +114,7 @@
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location_off);
         }
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
new file mode 100644
index 0000000..967c922
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, The Android Open Source Project
+ * Contributed by the Paranoid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.nfc.NfcAdapter;
+import android.provider.Settings;
+import android.widget.Switch;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Enable/Disable NFC **/
+public class NfcTile extends QSTile<QSTile.BooleanState> {
+
+    private NfcAdapter mAdapter;
+
+    private boolean mListening;
+
+    public NfcTile(Host host) {
+        super(host);
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        mListening = listening;
+        if (mListening) {
+            mContext.registerReceiver(mNfcReceiver,
+                    new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED));
+            if (mAdapter == null) {
+                try {
+                    mAdapter = NfcAdapter.getNfcAdapter(mContext);
+                } catch (UnsupportedOperationException e) {
+                    mAdapter = null;
+                }
+            }
+        } else {
+            mContext.unregisterReceiver(mNfcReceiver);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_NFC_SETTINGS);
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mAdapter == null) return;
+        MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
+        if (!mAdapter.isEnabled()) {
+            mAdapter.enable();
+        } else {
+            mAdapter.disable();
+        }
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        handleClick();
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_nfc_label);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
+        final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+        state.value = mAdapter == null ? false : mAdapter.isEnabled();
+        state.label = mContext.getString(R.string.quick_settings_nfc_label);
+        state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
+        state.contentDescription = state.label;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.QS_NFC;
+    }
+
+    @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return mContext.getString(R.string.quick_settings_nfc_on);
+        } else {
+            return mContext.getString(R.string.quick_settings_nfc_off);
+        }
+    }
+
+    private BroadcastReceiver mNfcReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 10fde30..b8ba28d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.app.NightDisplayController;
@@ -81,6 +82,7 @@
                 : R.drawable.ic_qs_night_display_off);
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName =
                 Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index cec5f15..2c0af17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -21,10 +21,12 @@
 import android.content.res.Configuration;
 
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.RotationLockController;
@@ -50,7 +52,7 @@
 
     public RotationLockTile(Host host) {
         super(host);
-        mController = host.getRotationLockController();
+        mController = Dependency.get(RotationLockController.class);
     }
 
     @Override
@@ -106,6 +108,7 @@
         state.contentDescription = getAccessibilityString(rotationLocked);
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     public static boolean isCurrentOrientationLockPortrait(RotationLockController controller,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
index 246c23e..c20c6bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -22,6 +22,7 @@
 import android.util.Pair;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -35,8 +36,8 @@
 
     public UserTile(Host host) {
         super(host);
-        mUserSwitcherController = host.getUserSwitcherController();
-        mUserInfoController = host.getUserInfoController();
+        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
+        mUserInfoController = Dependency.get(UserInfoController.class);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 3876c88..54b41ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
@@ -30,7 +31,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settingslib.wifi.AccessPoint;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
@@ -54,12 +57,14 @@
     private final QSTile.SignalState mStateBeforeClick = newTileState();
 
     protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
+    private final ActivityStarter mActivityStarter;
 
     public WifiTile(Host host) {
         super(host);
-        mController = host.getNetworkController();
+        mController = Dependency.get(NetworkController.class);
         mWifiController = mController.getAccessPointController();
         mDetailAdapter = (WifiDetailAdapter) createDetailAdapter();
+        mActivityStarter = Dependency.get(ActivityStarter.class);
     }
 
     @Override
@@ -104,7 +109,7 @@
     }
 
     @Override
-    protected void handleSecondaryClick() {
+    protected void handleClick() {
         // Secondary clicks are header clicks, just toggle.
         mState.copyTo(mStateBeforeClick);
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
@@ -112,9 +117,10 @@
     }
 
     @Override
-    protected void handleClick() {
+    protected void handleSecondaryClick() {
         if (!mWifiController.canConfigWifi()) {
-            mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_WIFI_SETTINGS));
+            mActivityStarter.postStartActivityDismissingKeyguard(
+                    new Intent(Settings.ACTION_WIFI_SETTINGS), 0);
             return;
         }
         showDetail(true);
@@ -191,6 +197,7 @@
         state.dualLabelContentDescription = wifiName;
         state.expandedAccessibilityClassName = Button.class.getName();
         state.minimalAccessibilityClassName = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
@@ -327,7 +334,7 @@
 
         @Override
         public void onSettingsActivityTriggered(Intent settingsIntent) {
-            mHost.startActivityDismissingKeyguard(settingsIntent);
+            mActivityStarter.postStartActivityDismissingKeyguard(settingsIntent, 0);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index ce7fbd3..ae4d6c9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -18,10 +18,12 @@
 
 import android.content.Intent;
 import android.provider.Settings;
+import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -40,7 +42,7 @@
 
     public WorkModeTile(Host host) {
         super(host);
-        mProfileController = host.getManagedProfileController();
+        mProfileController = Dependency.get(ManagedProfileController.class);
     }
 
     @Override
@@ -108,6 +110,7 @@
         }
         state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                 = Switch.class.getName();
+        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d5a6a58..06fadd1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -76,6 +76,8 @@
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
@@ -599,13 +601,12 @@
                 }
                 return true;
             }
-            case KeyEvent.KEYCODE_DPAD_UP: {
-                EventBus.getDefault().send(
-                        new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */));
-                return true;
-            }
-            case KeyEvent.KEYCODE_DPAD_DOWN: {
-                EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT: {
+                final Direction direction = NavigateTaskViewEvent.getDirectionFromKeyCode(keyCode);
+                EventBus.getDefault().send(new NavigateTaskViewEvent(direction));
                 return true;
             }
             case KeyEvent.KEYCODE_DEL:
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 914035b..a7f6b70 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -50,7 +50,7 @@
     /**
      * Returns the task to focus given the current launch state.
      */
-    public int getInitialFocusTaskIndex(int numTasks) {
+    public int getInitialFocusTaskIndex(int numTasks, boolean useGridLayout) {
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         if (launchedFromApp) {
@@ -66,6 +66,11 @@
                 return numTasks - 1;
             }
 
+            if (useGridLayout) {
+                // If coming from another app to the grid layout, focus the front most task
+                return numTasks - 1;
+            }
+
             // If coming from another app, focus the next task
             return Math.max(0, numTasks - 2);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 711f0c6..ff8d4bf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -17,12 +17,33 @@
 package com.android.systemui.recents;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 
 import android.os.SystemProperties;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.TaskStack;
+
+/**
+ * Represents the dock regions for each orientation.
+ */
+class DockRegion {
+    public static TaskStack.DockState[] PHONE_LANDSCAPE = {
+            // We only allow docking to the left in landscape for now on small devices
+            TaskStack.DockState.LEFT
+    };
+    public static TaskStack.DockState[] PHONE_PORTRAIT = {
+            // We only allow docking to the top for now on small devices
+            TaskStack.DockState.TOP
+    };
+    public static TaskStack.DockState[] TABLET_LANDSCAPE = {
+            TaskStack.DockState.LEFT,
+            TaskStack.DockState.RIGHT
+    };
+    public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
+}
 
 /**
  * Application resources that can be retrieved from the application context and are not specifically
@@ -63,12 +84,14 @@
     // Recents will layout task views in a grid mode when there's enough space in the screen.
     public boolean isGridEnabled;
 
+    private final Context mAppContext;
+
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
         SystemServicesProxy ssp = Recents.getSystemServices();
-        Context appContext = context.getApplicationContext();
-        Resources res = appContext.getResources();
+        mAppContext = context.getApplicationContext();
+        Resources res = mAppContext.getResources();
         fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
         svelteLevel = res.getInteger(R.integer.recents_svelte_level);
         isGridEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
@@ -86,4 +109,20 @@
     public RecentsActivityLaunchState getLaunchState() {
         return mLaunchState;
     }
+
+    /**
+     * Returns the preferred dock states for the current orientation.
+     * @return a list of dock states for device and its orientation
+     */
+    public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
+        boolean isLandscape = mAppContext.getResources().getConfiguration().orientation ==
+                Configuration.ORIENTATION_LANDSCAPE;
+        RecentsConfiguration config = Recents.getConfiguration();
+        if (config.isLargeScreen) {
+            return isLandscape ? DockRegion.TABLET_LANDSCAPE : DockRegion.TABLET_PORTRAIT;
+        } else {
+            return isLandscape ? DockRegion.PHONE_LANDSCAPE : DockRegion.PHONE_PORTRAIT;
+        }
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 0a56eac..cf6357b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -23,6 +23,7 @@
 import static android.view.View.MeasureSpec;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -60,6 +61,7 @@
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
+import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -131,6 +133,11 @@
                 loader.loadTasks(mContext, plan, launchOpts);
             }
         }
+
+        @Override
+        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+            EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId, snapshot));
+        }
     }
 
     protected static RecentsTaskLoadPlan sInstanceLoadPlan;
@@ -738,8 +745,12 @@
             Task toTask = new Task();
             TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask,
                     windowOverrideRect);
-            Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
-                    mThumbTransitionBitmapCache);
+            // When using a grid layout, the header is already visible on screen at the target
+            // location, making it unnecessary to draw it in the transition thumbnail.
+            Bitmap thumbnail = stackView.useGridLayout()
+                    ? mThumbTransitionBitmapCache.createAshmemBitmap()
+                    : drawThumbnailTransitionBitmap(toTask, toTransform,
+                            mThumbTransitionBitmapCache);
             if (thumbnail != null) {
                 RectF toTaskRect = toTransform.rect;
                 return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
@@ -770,7 +781,6 @@
         // Get the transform for the running task
         stackView.updateLayoutAlgorithm(true /* boundScroll */);
         stackView.updateToInitialState();
-        boolean isInSplitScreen = Recents.getSystemServices().hasDockedTask();
         stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null, windowOverrideRect);
         return mTmpTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
new file mode 100644
index 0000000..07c3b3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
@@ -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.systemui.recents.events.ui;
+
+import android.app.ActivityManager.TaskSnapshot;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when a task snapshot has changed.
+ */
+public class TaskSnapshotChangedEvent extends EventBus.Event {
+
+    public final int taskId;
+    public final TaskSnapshot taskSnapshot;
+
+    public TaskSnapshotChangedEvent(int taskId, TaskSnapshot taskSnapshot) {
+        this.taskId = taskId;
+        this.taskSnapshot = taskSnapshot;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
index b368bd3..e57fa2d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
@@ -30,10 +30,17 @@
     public final Task task;
     public final TaskView taskView;
     public final Point tlOffset;
+    public final boolean isUserTouchInitiated;
 
     public DragStartEvent(Task task, TaskView taskView, Point tlOffset) {
+        this(task, taskView, tlOffset, true);
+    }
+
+    public DragStartEvent(Task task, TaskView taskView, Point tlOffset,
+            boolean isUserTouchInitiated) {
         this.task = task;
         this.taskView = taskView;
         this.tlOffset = tlOffset;
+        this.isUserTouchInitiated = isUserTouchInitiated;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java
new file mode 100644
index 0000000..5508d26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/NavigateTaskViewEvent.java
@@ -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.
+ */
+
+package com.android.systemui.recents.events.ui.focus;
+
+import android.view.KeyEvent;
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Navigates the task view by arrow keys.
+ */
+public class NavigateTaskViewEvent extends EventBus.Event {
+    public enum Direction {
+        UNDEFINED, UP, DOWN, LEFT, RIGHT;
+    }
+
+    public Direction direction;
+    public NavigateTaskViewEvent(Direction direction) {
+        this.direction = direction;
+    }
+
+    public static Direction getDirectionFromKeyCode(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP:
+                return Direction.UP;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                return Direction.DOWN;
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                return Direction.LEFT;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                return Direction.RIGHT;
+            default:
+                return Direction.UNDEFINED;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 3587b89..49074a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -24,7 +24,9 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
@@ -77,6 +79,7 @@
 
 import com.android.internal.app.AssistUtils;
 import com.android.internal.os.BackgroundThread;
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.pip.tv.PipMenuActivity;
 import com.android.systemui.pip.tv.PipOnboardingActivity;
@@ -148,12 +151,32 @@
      */
     public abstract static class TaskStackListener {
         public void onTaskStackChanged() { }
+        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
         public void onActivityPinned() { }
-        public void onPinnedActivityRestartAttempt() { }
+        public void onPinnedActivityRestartAttempt(ComponentName sourceComponent) { }
         public void onPinnedStackAnimationEnded() { }
         public void onActivityForcedResizable(String packageName, int taskId) { }
         public void onActivityDismissingDockedStack() { }
         public void onTaskProfileLocked(int taskId, int userId) { }
+
+        /**
+         * Checks that the current user matches the user's SystemUI process. Since
+         * {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
+         * TaskStackListener should make this call to verify that we don't act on events from other
+         * user's processes.
+         */
+        protected final boolean checkCurrentUserId(boolean debug) {
+            int processUserId = UserHandle.myUserId();
+            int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+            if (processUserId != currentUserId) {
+                if (debug) {
+                    Log.d(TAG, "UID mismatch. SystemUI is running uid=" + processUserId
+                            + " and the current user is uid=" + currentUserId);
+                }
+                return false;
+            }
+            return true;
+        }
     }
 
     /**
@@ -175,9 +198,11 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt() throws RemoteException{
+        public void onPinnedActivityRestartAttempt(ComponentName sourceComponent)
+                throws RemoteException{
             mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
-            mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+            mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, sourceComponent)
+                    .sendToTarget();
         }
 
         @Override
@@ -202,6 +227,12 @@
         public void onTaskProfileLocked(int taskId, int userId) {
             mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
         }
+
+        @Override
+        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
+                throws RemoteException {
+            mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+        }
     };
 
     /**
@@ -591,17 +622,17 @@
     /** Returns the top task thumbnail for the given task id */
     public ThumbnailData getTaskThumbnail(int taskId) {
         if (mAm == null) return null;
-        ThumbnailData thumbnailData = new ThumbnailData();
 
         // If we are mocking, then just return a dummy thumbnail
         if (RecentsDebugFlags.Static.EnableMockTasks) {
+            ThumbnailData thumbnailData = new ThumbnailData();
             thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
                     mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
             thumbnailData.thumbnail.eraseColor(0xff333333);
             return thumbnailData;
         }
 
-        getThumbnail(taskId, thumbnailData);
+        ThumbnailData thumbnailData = getThumbnail(taskId);
         if (thumbnailData.thumbnail != null && !ActivityManager.ENABLE_TASK_SNAPSHOTS) {
             thumbnailData.thumbnail.setHasAlpha(false);
             // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
@@ -621,11 +652,12 @@
     /**
      * Returns a task thumbnail from the activity manager
      */
-    public void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) {
+    public @NonNull ThumbnailData getThumbnail(int taskId) {
         if (mAm == null) {
-            return;
+            return new ThumbnailData();
         }
 
+        final ThumbnailData thumbnailData;
         if (ActivityManager.ENABLE_TASK_SNAPSHOTS) {
             ActivityManager.TaskSnapshot snapshot = null;
             try {
@@ -634,16 +666,14 @@
                 Log.w(TAG, "Failed to retrieve snapshot", e);
             }
             if (snapshot != null) {
-                thumbnailDataOut.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
-                thumbnailDataOut.orientation = snapshot.getOrientation();
-                thumbnailDataOut.insets.set(snapshot.getContentInsets());
+                thumbnailData = ThumbnailData.createFromTaskSnapshot(snapshot);
             } else {
-                thumbnailDataOut.thumbnail = null;
+                return new ThumbnailData();
             }
         } else {
             ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
             if (taskThumbnail == null) {
-                return;
+                return new ThumbnailData();
             }
 
             Bitmap thumbnail = taskThumbnail.mainThumbnail;
@@ -658,10 +688,12 @@
                 } catch (IOException e) {
                 }
             }
-            thumbnailDataOut.thumbnail = thumbnail;
-            thumbnailDataOut.orientation = taskThumbnail.thumbnailInfo.screenOrientation;
-            thumbnailDataOut.insets.setEmpty();
+            thumbnailData = new ThumbnailData();
+            thumbnailData.thumbnail = thumbnail;
+            thumbnailData.orientation = taskThumbnail.thumbnailInfo.screenOrientation;
+            thumbnailData.insets.setEmpty();
         }
+        return thumbnailData;
     }
 
     /**
@@ -1172,12 +1204,13 @@
 
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
-        private static final int ON_ACTIVITY_PINNED = 2;
-        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
-        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
-        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
-        private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 6;
-        private static final int ON_TASK_PROFILE_LOCKED = 7;
+        private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+        private static final int ON_ACTIVITY_PINNED = 3;
+        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
+        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 5;
+        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
+        private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
+        private static final int ON_TASK_PROFILE_LOCKED = 8;
 
         @Override
         public void handleMessage(Message msg) {
@@ -1188,6 +1221,13 @@
                     }
                     break;
                 }
+                case ON_TASK_SNAPSHOT_CHANGED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+                                (TaskSnapshot) msg.obj);
+                    }
+                    break;
+                }
                 case ON_ACTIVITY_PINNED: {
                     for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                         mTaskStackListeners.get(i).onActivityPinned();
@@ -1196,7 +1236,8 @@
                 }
                 case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
                     for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                        mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
+                        mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
+                                (ComponentName) msg.obj);
                     }
                     break;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 6ea51e5..ededf96 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -209,7 +209,8 @@
                             // When svelte, we trim the memory to just the visible thumbnails when
                             // leaving, so don't thrash the cache as the user scrolls (just load
                             // them from scratch each time)
-                            if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE) {
+                            if (config.svelteLevel < RecentsConfiguration.SVELTE_LIMIT_CACHE
+                                    && !ActivityManager.ENABLE_TASK_SNAPSHOTS) {
                                 mThumbnailCache.put(t.key, cachedThumbnailData);
                             }
                         }
@@ -553,7 +554,9 @@
                 // Load the thumbnail from the system
                 thumbnailData = ssp.getTaskThumbnail(taskKey.id);
                 if (thumbnailData.thumbnail != null) {
-                    mThumbnailCache.put(taskKey, thumbnailData);
+                    if (!ActivityManager.ENABLE_TASK_SNAPSHOTS) {
+                        mThumbnailCache.put(taskKey, thumbnailData);
+                    }
                     return thumbnailData.thumbnail;
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 178cb9f..9b25ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -247,6 +247,9 @@
      */
     public static class DockState implements DropTarget {
 
+        public static final int DOCK_AREA_BG_COLOR = 0xFFffffff;
+        public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000;
+
         // The rotation to apply to the hint text
         @Retention(RetentionPolicy.SOURCE)
         @IntDef({HORIZONTAL, VERTICAL})
@@ -319,7 +322,8 @@
             private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
                     int hintTextResId) {
                 dockAreaAlpha = areaAlpha;
-                dockAreaOverlay = new ColorDrawable(0xFFffffff);
+                dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
+                        ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
                 dockAreaOverlay.setAlpha(0);
                 hintTextAlpha = hintAlpha;
                 hintTextOrientation = hintOrientation;
@@ -435,7 +439,7 @@
          * @param createMode used to pass to ActivityManager to dock the task
          * @param touchArea the area in which touch will initiate this dock state
          * @param dockArea the visible dock area
-         * @param expandedTouchDockArea the areain which touch will continue to dock after entering
+         * @param expandedTouchDockArea the area in which touch will continue to dock after entering
          *                              the initial touch area.  This is also the new dock area to
          *                              draw.
          */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
index 18735ac..09a3712 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.model;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 
@@ -23,7 +24,17 @@
  * Data for a single thumbnail.
  */
 public class ThumbnailData {
+
+    // TODO: Make these final once the non-snapshot path is removed.
     public Bitmap thumbnail;
     public int orientation;
     public final Rect insets = new Rect();
+
+    public static ThumbnailData createFromTaskSnapshot(TaskSnapshot snapshot) {
+        ThumbnailData out = new ThumbnailData();
+        out.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
+        out.insets.set(snapshot.getContentInsets());
+        out.orientation = snapshot.getOrientation();
+        return out;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index d64a676..79a774f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -30,6 +30,7 @@
 import android.util.Log;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 
 /**
@@ -90,8 +91,10 @@
         mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
         mCornerShadowPaint.setStyle(Paint.Style.FILL);
         mCornerShadowPaint.setDither(true);
-        mCornerRadius = resources.getDimensionPixelSize(
-                R.dimen.recents_task_view_rounded_corners_radius);
+        mCornerRadius = Recents.getConfiguration().isGridEnabled ?
+                resources.getDimensionPixelSize(
+                    R.dimen.recents_grid_task_view_rounded_corners_radius) :
+                resources.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         mCardBounds = new RectF();
         mEdgeShadowPaint = new Paint(mCornerShadowPaint);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index ee79330..8f9c457 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -454,7 +454,7 @@
     }
 
     public final void onBusEvent(DragStartEvent event) {
-        updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
+        updateVisibleDockRegions(Recents.getConfiguration().getDockStatesForCurrentOrientation(),
                 true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
                 TaskStack.DockState.NONE.viewState.hintTextAlpha,
                 true /* animateAlpha */, false /* animateBounds */);
@@ -471,7 +471,8 @@
 
     public final void onBusEvent(DragDropTargetChangedEvent event) {
         if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
-            updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
+            updateVisibleDockRegions(
+                    Recents.getConfiguration().getDockStatesForCurrentOrientation(),
                     true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
                     TaskStack.DockState.NONE.viewState.hintTextAlpha,
                     true /* animateAlpha */, true /* animateBounds */);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index d3ec984..db0c95e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -28,7 +28,6 @@
 
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
@@ -45,25 +44,6 @@
 import java.util.ArrayList;
 
 /**
- * Represents the dock regions for each orientation.
- */
-class DockRegion {
-    public static TaskStack.DockState[] PHONE_LANDSCAPE = {
-            // We only allow docking to the left in landscape for now on small devices
-            TaskStack.DockState.LEFT
-    };
-    public static TaskStack.DockState[] PHONE_PORTRAIT = {
-            // We only allow docking to the top for now on small devices
-            TaskStack.DockState.TOP
-    };
-    public static TaskStack.DockState[] TABLET_LANDSCAPE = {
-            TaskStack.DockState.LEFT,
-            TaskStack.DockState.RIGHT
-    };
-    public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
-}
-
-/**
  * Handles touch events for a RecentsView.
  */
 public class RecentsViewTouchHandler {
@@ -111,20 +91,6 @@
     }
 
     /**
-     * Returns the preferred dock states for the current orientation.
-     */
-    public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
-        boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
-                Configuration.ORIENTATION_LANDSCAPE;
-        RecentsConfiguration config = Recents.getConfiguration();
-        if (config.isLargeScreen) {
-            return isLandscape ? DockRegion.TABLET_LANDSCAPE : DockRegion.TABLET_PORTRAIT;
-        } else {
-            return isLandscape ? DockRegion.PHONE_LANDSCAPE : DockRegion.PHONE_PORTRAIT;
-        }
-    }
-
-    /**
      * Returns the set of visible dock states for this current drag.
      */
     public ArrayList<TaskStack.DockState> getVisibleDockStates() {
@@ -162,10 +128,14 @@
         mRv.getLocationInWindow(recentsViewLocation);
         mTaskViewOffset.set(mTaskView.getLeft() - recentsViewLocation[0] + event.tlOffset.x,
                 mTaskView.getTop() - recentsViewLocation[1] + event.tlOffset.y);
-        float x = mDownPos.x - mTaskViewOffset.x;
-        float y = mDownPos.y - mTaskViewOffset.y;
-        mTaskView.setTranslationX(x);
-        mTaskView.setTranslationY(y);
+
+        // Change space coordinates relative to the view to RecentsView when user initiates a touch
+        if (event.isUserTouchInitiated) {
+            float x = mDownPos.x - mTaskViewOffset.x;
+            float y = mDownPos.y - mTaskViewOffset.y;
+            mTaskView.setTranslationX(x);
+            mTaskView.setTranslationY(y);
+        }
 
         mVisibleDockStates.clear();
         if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()
@@ -176,7 +146,8 @@
                 EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
             } else {
                 // Add the dock state drop targets (these take priority)
-                TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
+                TaskStack.DockState[] dockStates = Recents.getConfiguration()
+                        .getDockStatesForCurrentOrientation();
                 for (TaskStack.DockState dockState : dockStates) {
                     registerDropTargetForCurrentDrag(dockState);
                     dockState.update(mRv.getContext());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index ed86d4c..a2ee4c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -105,6 +105,7 @@
     private static final Interpolator ENTER_WHILE_DOCKING_INTERPOLATOR =
             Interpolators.LINEAR_OUT_SLOW_IN;
 
+    private final int mEnterAndExitFromHomeTranslationOffset;
     private TaskStackView mStackView;
 
     private TaskViewTransform mTmpTransform = new TaskViewTransform();
@@ -113,6 +114,8 @@
 
     public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
         mStackView = stackView;
+        mEnterAndExitFromHomeTranslationOffset = Recents.getConfiguration().isGridEnabled
+                ? 0 : DOUBLE_FRAME_OFFSET_MS;
     }
 
     /**
@@ -260,7 +263,7 @@
                 AnimationProps taskAnimation = new AnimationProps()
                         .setInitialPlayTime(AnimationProps.BOUNDS,
                                 Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
-                                        DOUBLE_FRAME_OFFSET_MS)
+                                        mEnterAndExitFromHomeTranslationOffset)
                         .setStartDelay(AnimationProps.ALPHA,
                                 Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
                                         FRAME_OFFSET_MS)
@@ -321,7 +324,7 @@
             AnimationProps taskAnimation;
             if (animated) {
                 int delay = Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS , taskIndexFromFront) *
-                        DOUBLE_FRAME_OFFSET_MS;
+                        mEnterAndExitFromHomeTranslationOffset;
                 taskAnimation = new AnimationProps()
                         .setStartDelay(AnimationProps.BOUNDS, delay)
                         .setDuration(AnimationProps.BOUNDS, EXIT_TO_HOME_TRANSLATION_DURATION)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index a58896a..4fa7ecb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -291,6 +291,9 @@
     @ViewDebug.ExportedProperty(category="recents")
     private int mStackBottomOffset;
 
+    /** The height, in pixels, of each task view's title bar. */
+    private int mTitleBarHeight;
+
     // The paths defining the motion of the tasks when the stack is focused and unfocused
     private Path mUnfocusedCurve;
     private Path mFocusedCurve;
@@ -403,6 +406,14 @@
         mBaseBottomMargin = res.getDimensionPixelSize(R.dimen.recents_layout_bottom_margin);
         mFreeformStackGap =
                 res.getDimensionPixelSize(R.dimen.recents_freeform_layout_bottom_margin);
+        mTitleBarHeight = getDimensionForDevice(mContext,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land,
+                R.dimen.recents_grid_task_view_header_height);
     }
 
     /**
@@ -903,12 +914,17 @@
      * Transforms the given {@param transformOut} to the screen coordinates, overriding the current
      * window rectangle with {@param windowOverrideRect} if non-null.
      */
-    public TaskViewTransform transformToScreenCoordinates(TaskViewTransform transformOut,
+    TaskViewTransform transformToScreenCoordinates(TaskViewTransform transformOut,
             Rect windowOverrideRect) {
         Rect windowRect = windowOverrideRect != null
                 ? windowOverrideRect
                 : Recents.getSystemServices().getWindowRect();
         transformOut.rect.offset(windowRect.left, windowRect.top);
+        if (useGridLayout()) {
+            // Draw the thumbnail a little lower to perfectly coincide with the view we are
+            // transitioning to, where the header bar has already been drawn.
+            transformOut.rect.offset(0, mTitleBarHeight);
+        }
         return transformOut;
     }
 
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 b7686ce..8ae7a83 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -70,6 +70,7 @@
 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
@@ -86,6 +87,7 @@
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
@@ -93,6 +95,7 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import com.android.systemui.recents.views.grid.GridTaskView;
+import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -206,6 +209,10 @@
     private int mLastWidth;
     private int mLastHeight;
 
+    // We keep track of the task view focused by user interaction and draw a frame around it in the
+    // grid layout.
+    private TaskViewFocusFrame mTaskViewFocusFrame;
+
     // A convenience update listener to request updating clipping of tasks
     private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
             new ValueAnimator.AnimatorUpdateListener() {
@@ -259,12 +266,21 @@
         mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
         mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
         mAnimationHelper = new TaskStackAnimationHelper(context, this);
-        mTaskCornerRadiusPx = res.getDimensionPixelSize(
-                R.dimen.recents_task_view_rounded_corners_radius);
+        mTaskCornerRadiusPx = Recents.getConfiguration().isGridEnabled ?
+                res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) :
+                res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         mDividerSize = ssp.getDockedDividerSize(context);
         mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
         mDisplayRect = ssp.getDisplayRect();
 
+        // Create a frame to draw around the focused task view
+        if (Recents.getConfiguration().isGridEnabled) {
+            mTaskViewFocusFrame = new TaskViewFocusFrame(mContext, this,
+                mLayoutAlgorithm.mTaskGridLayoutAlgorithm);
+            addView(mTaskViewFocusFrame);
+            getViewTreeObserver().addOnGlobalFocusChangeListener(mTaskViewFocusFrame);
+        }
+
         int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                 R.integer.recents_task_bar_dismiss_delay_seconds);
         mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
@@ -878,7 +894,7 @@
      *
      * @return whether or not the stack will scroll as a part of this focus change
      */
-    private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
+    public boolean setFocusedTask(int taskIndex, boolean scrollToTask,
             final boolean requestViewFocus) {
         return setFocusedTask(taskIndex, scrollToTask, requestViewFocus, 0);
     }
@@ -888,7 +904,7 @@
      *
      * @return whether or not the stack will scroll as a part of this focus change
      */
-    private boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
+    public boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
             boolean requestViewFocus, int timerIndicatorDuration) {
         // Find the next task to focus
         int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
@@ -940,6 +956,10 @@
                     newFocusedTaskView.setFocusedState(true, requestViewFocus);
                 }
             }
+            // Any time a task view gets the focus, we move the focus frame around it.
+            if (mTaskViewFocusFrame != null) {
+                mTaskViewFocusFrame.moveGridTaskViewFocus(getChildViewForTask(newFocusedTask));
+            }
         }
         return willScroll;
     }
@@ -1005,20 +1025,28 @@
             float stackScroll = mStackScroller.getStackScroll();
             ArrayList<Task> tasks = mStack.getStackTasks();
             int taskCount = tasks.size();
-            if (forward) {
-                // Walk backwards and focus the next task smaller than the current stack scroll
-                for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
-                    float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
-                    if (Float.compare(taskP, stackScroll) <= 0) {
-                        break;
-                    }
-                }
+            if (useGridLayout()) {
+                // For the grid layout, we directly set focus to the most recently used task
+                // no matter we're moving forwards or backwards.
+                newIndex = taskCount - 1;
             } else {
-                // Walk forwards and focus the next task larger than the current stack scroll
-                for (newIndex = 0; newIndex < taskCount; newIndex++) {
-                    float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
-                    if (Float.compare(taskP, stackScroll) >= 0) {
-                        break;
+                // For the grid layout we pick a proper task to focus, according to the current
+                // stack scroll.
+                if (forward) {
+                    // Walk backwards and focus the next task smaller than the current stack scroll
+                    for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
+                        float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
+                        if (Float.compare(taskP, stackScroll) <= 0) {
+                            break;
+                        }
+                    }
+                } else {
+                    // Walk forwards and focus the next task larger than the current stack scroll
+                    for (newIndex = 0; newIndex < taskCount; newIndex++) {
+                        float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
+                        if (Float.compare(taskP, stackScroll) >= 0) {
+                            break;
+                        }
                     }
                 }
             }
@@ -1037,20 +1065,23 @@
     /**
      * Resets the focused task.
      */
-    void resetFocusedTask(Task task) {
+    public void resetFocusedTask(Task task) {
         if (task != null) {
             TaskView tv = getChildViewForTask(task);
             if (tv != null) {
                 tv.setFocusedState(false, false /* requestViewFocus */);
             }
         }
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+        }
         mFocusedTask = null;
     }
 
     /**
      * Returns the focused task.
      */
-    Task getFocusedTask() {
+    public Task getFocusedTask() {
         return mFocusedTask;
     }
 
@@ -1253,6 +1284,9 @@
         for (int i = 0; i < taskViewCount; i++) {
             measureTaskView(mTmpTaskViews.get(i));
         }
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.measure();
+        }
 
         setMeasuredDimension(width, height);
         mLastWidth = width;
@@ -1287,6 +1321,9 @@
         for (int i = 0; i < taskViewCount; i++) {
             layoutTaskView(changed, mTmpTaskViews.get(i));
         }
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.layout();
+        }
 
         if (changed) {
             if (mStackScroller.isScrollOutOfBounds()) {
@@ -1339,10 +1376,19 @@
         // until after the enter-animation
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount());
-        if (focusedTaskIndex != -1) {
-            setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
-                    false /* requestViewFocus */);
+
+        // We set the initial focused task view iff the following conditions are satisfied:
+        // 1. Recents is showing task views in stack layout.
+        // 2. Recents is launched with ALT + TAB.
+        boolean setFocusOnFirstLayout = !useGridLayout() ||
+            Recents.getConfiguration().getLaunchState().launchedWithAltTab;
+        if (setFocusOnFirstLayout) {
+            int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount(),
+                useGridLayout());
+            if (focusedTaskIndex != -1) {
+                setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
+                        false /* requestViewFocus */);
+            }
         }
         updateStackActionButtonVisibility();
     }
@@ -1443,6 +1489,11 @@
         // Remove the task from the ignored set
         removeIgnoreTask(removedTask);
 
+        // Resize the grid layout task view focus frame
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.resize();
+        }
+
         // If requested, relayout with the given animation
         if (animation != null) {
             updateLayoutAlgorithm(true /* boundScroll */);
@@ -1740,10 +1791,18 @@
         int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
         animateFreeformWorkspaceBackgroundAlpha(0, new AnimationProps(taskViewExitToHomeDuration,
                 Interpolators.FAST_OUT_SLOW_IN));
+
+        // Dismiss the grid task view focus frame
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+        }
     }
 
     public final void onBusEvent(DismissFocusedTaskViewEvent event) {
         if (mFocusedTask != null) {
+            if (mTaskViewFocusFrame != null) {
+                mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+            }
             TaskView tv = getChildViewForTask(mFocusedTask);
             if (tv != null) {
                 tv.dismissTask();
@@ -1812,6 +1871,26 @@
         setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
     }
 
+    public final void onBusEvent(NavigateTaskViewEvent event) {
+        if (useGridLayout()) {
+            final int taskCount = mStack.getTaskCount();
+            final int currentIndex = mStack.indexOfStackTask(getFocusedTask());
+            final int nextIndex = mLayoutAlgorithm.mTaskGridLayoutAlgorithm.navigateFocus(taskCount,
+                    currentIndex, event.direction);
+            setFocusedTask(nextIndex, false, true);
+        } else {
+            switch (event.direction) {
+                case UP:
+                    EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
+                    break;
+                case DOWN:
+                    EventBus.getDefault().send(
+                        new FocusNextTaskViewEvent(0 /* timerIndicatorDuration */));
+                    break;
+            }
+        }
+    }
+
     public final void onBusEvent(UserInteractionEvent event) {
         // Poke the doze trigger on user interaction
         mUIDozeTrigger.poke();
@@ -2073,6 +2152,12 @@
         mResetToInitialStateWhenResized = true;
     }
 
+    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+        if (!event.visible && mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+        }
+    }
+
     public void reloadOnConfigurationChange() {
         mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
         mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 33fa3b0..5817e92 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -342,8 +342,9 @@
                         mSv.invalidate();
                     }
 
-                    // Reset the focused task after the user has scrolled
-                    if (!mSv.mTouchExplorationEnabled) {
+                    // Reset the focused task after the user has scrolled, but we have no scrolling
+                    // in grid layout and therefore we don't want to reset the focus there.
+                    if (!mSv.mTouchExplorationEnabled && !mSv.useGridLayout()) {
                         mSv.resetFocusedTask(mSv.getFocusedTask());
                     }
                 } else if (mActiveTaskView == null) {
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 5f37349..e941c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -22,7 +22,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Outline;
@@ -184,6 +183,7 @@
         }
         setOutlineProvider(mViewBounds);
         setOnLongClickListener(this);
+        setAccessibilityDelegate(new TaskViewAccessibilityDelegate(this));
     }
 
     /** Set callback */
@@ -258,6 +258,11 @@
     }
 
     @Override
+    public void addChildrenForAccessibility(ArrayList<View> outChildren) {
+        // Prevent any children from being focusable during talkback
+    }
+
+    @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
new file mode 100644
index 0000000..759daf1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.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.recents.views;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.recents.model.TaskStack;
+
+public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
+    private static final String TAG = "TaskViewAccessibilityDelegate";
+
+    private final TaskView mTaskView;
+
+    protected static final int OPEN = R.id.action_open;
+    protected static final int DIMISS = R.id.action_dimiss;
+    protected static final int SPLIT_TASK_TOP = R.id.action_split_task_to_top;
+    protected static final int SPLIT_TASK_LEFT = R.id.action_split_task_to_left;
+    protected static final int SPLIT_TASK_RIGHT = R.id.action_split_task_to_right;
+
+    protected final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
+
+    public TaskViewAccessibilityDelegate(TaskView taskView) {
+        mTaskView = taskView;
+        Context context = taskView.getContext();
+        mActions.put(OPEN, new AccessibilityAction(OPEN,
+                context.getString(R.string.recents_accessibility_open)));
+        mActions.put(DIMISS, new AccessibilityAction(DIMISS,
+                context.getString(R.string.recents_accessibility_dismissed)));
+        mActions.put(SPLIT_TASK_TOP, new AccessibilityAction(SPLIT_TASK_TOP,
+                context.getString(R.string.recents_accessibility_split_screen_top)));
+        mActions.put(SPLIT_TASK_LEFT, new AccessibilityAction(SPLIT_TASK_LEFT,
+                context.getString(R.string.recents_accessibility_split_screen_left)));
+        mActions.put(SPLIT_TASK_RIGHT, new AccessibilityAction(SPLIT_TASK_RIGHT,
+                context.getString(R.string.recents_accessibility_split_screen_right)));
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(host, info);
+        info.addAction(mActions.get(OPEN));
+        info.addAction(mActions.get(DIMISS));
+        if (ActivityManager.supportsSplitScreenMultiWindow()
+                && !Recents.getSystemServices().hasDockedTask()) {
+            TaskStack.DockState[] dockStates = Recents.getConfiguration()
+                    .getDockStatesForCurrentOrientation();
+            for (TaskStack.DockState dockState: dockStates) {
+                if (dockState == TaskStack.DockState.TOP) {
+                    info.addAction(mActions.get(SPLIT_TASK_TOP));
+                } else if (dockState == TaskStack.DockState.LEFT) {
+                    info.addAction(mActions.get(SPLIT_TASK_LEFT));
+                } else if (dockState == TaskStack.DockState.RIGHT) {
+                    info.addAction(mActions.get(SPLIT_TASK_RIGHT));
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean performAccessibilityAction(View host, int action, Bundle args) {
+        if (action == OPEN) {
+            mTaskView.onClick(host);
+        } else if (action == DIMISS) {
+            mTaskView.dismissTask();
+        } else if (action == SPLIT_TASK_TOP) {
+            simulateDragIntoMultiwindow(TaskStack.DockState.TOP);
+        } else if (action == SPLIT_TASK_LEFT) {
+            simulateDragIntoMultiwindow(TaskStack.DockState.LEFT);
+        } else if (action == SPLIT_TASK_RIGHT) {
+            simulateDragIntoMultiwindow(TaskStack.DockState.RIGHT);
+        } else {
+            return super.performAccessibilityAction(host, action, args);
+        }
+        return true;
+    }
+
+    /** Simulate a user drag event to split the screen to the respected side */
+    private void simulateDragIntoMultiwindow(TaskStack.DockState dockState) {
+        int orientation = Utilities.getAppConfiguration(mTaskView.getContext()).orientation;
+        EventBus.getDefault().send(new DragStartEvent(mTaskView.getTask(), mTaskView,
+                new Point(0,0), false /* isUserTouchInitiated */));
+        EventBus.getDefault().send(new DragEndEvent(mTaskView.getTask(), mTaskView, dockState));
+    }
+}
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 c0cc83f..0777163 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -201,7 +201,9 @@
         Resources res = context.getResources();
         mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light);
         mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
-        mCornerRadius = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
+        mCornerRadius = Recents.getConfiguration().isGridEnabled ?
+                res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) :
+                res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         mHighlightHeight = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
         mTaskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color);
         mTaskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index e3bf1df..4ac0f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.views;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -35,6 +36,9 @@
 import android.view.ViewDebug;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.EventBus.Event;
+import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.ThumbnailData;
@@ -57,11 +61,11 @@
 
     // Drawing
     @ViewDebug.ExportedProperty(category="recents")
-    private Rect mTaskViewRect = new Rect();
+    protected Rect mTaskViewRect = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    private Rect mThumbnailRect = new Rect();
+    protected Rect mThumbnailRect = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    private float mThumbnailScale;
+    protected float mThumbnailScale;
     private float mFullscreenThumbnailScale;
     /** The height, in pixels, of the task view's title bar. */
     private int mTitleBarHeight;
@@ -69,14 +73,14 @@
     private boolean mOverlayHeaderOnThumbnailActionBar = true;
     private ThumbnailData mThumbnailData;
 
-    private int mCornerRadius;
+    protected int mCornerRadius;
     @ViewDebug.ExportedProperty(category="recents")
     private float mDimAlpha;
     private Matrix mMatrix = new Matrix();
-    private Paint mDrawPaint = new Paint();
+    protected Paint mDrawPaint = new Paint();
     private Paint mLockedPaint = new Paint();
-    private Paint mBgFillPaint = new Paint();
-    private BitmapShader mBitmapShader;
+    protected Paint mBgFillPaint = new Paint();
+    protected BitmapShader mBitmapShader;
     private LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
 
     // Clip the top of the thumbnail against the opaque header bar that overlaps this view
@@ -111,8 +115,12 @@
         mCornerRadius = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         mBgFillPaint.setColor(Color.WHITE);
         mLockedPaint.setColor(Color.WHITE);
-        mFullscreenThumbnailScale = res.getFraction(
-                com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
+        if (ActivityManager.ENABLE_TASK_SNAPSHOTS) {
+            mFullscreenThumbnailScale = 1f;
+        } else {
+            mFullscreenThumbnailScale = res.getFraction(
+                    com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
+        }
         mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height);
     }
 
@@ -347,6 +355,7 @@
             mBgFillPaint.setColor(t.colorBackground);
         }
         mLockedPaint.setColor(t.colorPrimary);
+        EventBus.getDefault().register(this);
     }
 
     /**
@@ -361,6 +370,14 @@
     void unbindFromTask() {
         mTask = null;
         setThumbnail(null);
+        EventBus.getDefault().unregister(this);
+    }
+
+    public final void onBusEvent(TaskSnapshotChangedEvent event) {
+        if (mTask == null || event.taskId != mTask.key.id || event.taskSnapshot == null) {
+            return;
+        }
+        setThumbnail(ThumbnailData.createFromTaskSnapshot(event.taskSnapshot));
     }
 
     public void dump(String prefix, PrintWriter writer) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
new file mode 100644
index 0000000..2c3e42b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/GridTaskViewThumbnail.java
@@ -0,0 +1,185 @@
+/*
+ * 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.recents.views.grid;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.util.AttributeSet;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.views.TaskViewThumbnail;
+
+public class GridTaskViewThumbnail extends TaskViewThumbnail {
+
+    private Path mThumbnailOutline;
+    private Path mRestBackgroundOutline;
+    private Path mFullBackgroundOutline;
+    // True if either this view's size or thumbnail scale has changed and mThumbnailOutline should
+    // be updated.
+    private boolean mUpdateThumbnailOutline = true;
+
+    public GridTaskViewThumbnail(Context context) {
+        this(context, null);
+    }
+
+    public GridTaskViewThumbnail(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public GridTaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr,
+        int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mCornerRadius = getResources().getDimensionPixelSize(
+                R.dimen.recents_grid_task_view_rounded_corners_radius);
+    }
+
+    /**
+     * Called when the task view frame changes, allowing us to move the contents of the header
+     * to match the frame changes.
+     */
+    public void onTaskViewSizeChanged(int width, int height) {
+        mUpdateThumbnailOutline = true;
+        super.onTaskViewSizeChanged(width, height);
+    }
+
+    /**
+     * Updates the scale of the bitmap relative to this view.
+     */
+    public void updateThumbnailMatrix() {
+        mUpdateThumbnailOutline = true;
+        super.updateThumbnailMatrix();
+    }
+
+    private void updateThumbnailOutline() {
+        final int titleHeight = getResources().getDimensionPixelSize(
+            R.dimen.recents_grid_task_view_header_height);
+        final int viewWidth = mTaskViewRect.width();
+        final int viewHeight = mTaskViewRect.height() - titleHeight;
+        final int thumbnailWidth = Math.min(viewWidth,
+            (int) (mThumbnailRect.width() * mThumbnailScale));
+        final int thumbnailHeight = Math.min(viewHeight,
+            (int) (mThumbnailRect.height() * mThumbnailScale));
+        // Draw the thumbnail, we only round the bottom corners:
+        //
+        // outerLeft                outerRight
+        //    <----------------------->            mRestBackgroundOutline
+        //    _________________________            (thumbnailWidth < viewWidth)
+        //    |_______________________| outerTop     A ____ B
+        //    |                       |    ↑           |  |
+        //    |                       |    |           |  |
+        //    |                       |    |           |  |
+        //    |                       |    |           |  | C
+        //    \_______________________/    ↓           |__/
+        //  mCornerRadius             outerBottom    E    D
+        //
+        //  mRestBackgroundOutline (thumbnailHeight < viewHeight)
+        //  A _________________________ B
+        //    |                       | C
+        //  F \_______________________/
+        //    E                       D
+        final int outerLeft = 0;
+        final int outerTop = 0;
+        final int outerRight = outerLeft + thumbnailWidth;
+        final int outerBottom = outerTop + thumbnailHeight;
+        mThumbnailOutline = new Path();
+        mThumbnailOutline.moveTo(outerLeft, outerTop);
+        mThumbnailOutline.lineTo(outerRight, outerTop);
+        mThumbnailOutline.lineTo(outerRight, outerBottom - mCornerRadius);
+        mThumbnailOutline.arcTo(outerRight -  2 * mCornerRadius, outerBottom - 2 * mCornerRadius,
+                outerRight, outerBottom, 0, 90, false);
+        mThumbnailOutline.lineTo(outerLeft + mCornerRadius, outerBottom);
+        mThumbnailOutline.arcTo(outerLeft, outerBottom - 2 * mCornerRadius,
+                outerLeft + 2 * mCornerRadius, outerBottom, 90, 90, false);
+        mThumbnailOutline.lineTo(outerLeft, outerTop);
+        mThumbnailOutline.close();
+
+        if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+            if (thumbnailWidth < viewWidth) {
+                final int l = Math.max(0, outerRight - mCornerRadius);
+                final int r = outerRight;
+                final int t = outerTop;
+                final int b = outerBottom;
+                mRestBackgroundOutline = new Path();
+                mRestBackgroundOutline.moveTo(l, t); // A
+                mRestBackgroundOutline.lineTo(r, t); // B
+                mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C
+                mRestBackgroundOutline.arcTo(r -  2 * mCornerRadius, b - 2 * mCornerRadius, r, b,
+                        0, 90, false); // D
+                mRestBackgroundOutline.lineTo(l, b); // E
+                mRestBackgroundOutline.lineTo(l, t); // A
+                mRestBackgroundOutline.close();
+
+            }
+            if (thumbnailHeight < viewHeight) {
+                final int l = outerLeft;
+                final int r = outerRight;
+                final int t = Math.max(0, thumbnailHeight - mCornerRadius);
+                final int b = outerBottom;
+                mRestBackgroundOutline = new Path();
+                mRestBackgroundOutline.moveTo(l, t); // A
+                mRestBackgroundOutline.lineTo(r, t); // B
+                mRestBackgroundOutline.lineTo(r, b - mCornerRadius); // C
+                mRestBackgroundOutline.arcTo(r -  2 * mCornerRadius, b - 2 * mCornerRadius, r, b,
+                        0, 90, false); // D
+                mRestBackgroundOutline.lineTo(l + mCornerRadius, b); // E
+                mRestBackgroundOutline.arcTo(l, b - 2 * mCornerRadius, l + 2 * mCornerRadius, b,
+                        90, 90, false); // F
+                mRestBackgroundOutline.lineTo(l, t); // A
+                mRestBackgroundOutline.close();
+
+            }
+        } else {
+            mFullBackgroundOutline = mThumbnailOutline;
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final int titleHeight = getResources().getDimensionPixelSize(
+            R.dimen.recents_grid_task_view_header_height);
+        final int viewWidth = mTaskViewRect.width();
+        final int viewHeight = mTaskViewRect.height() - titleHeight;
+        final int thumbnailWidth = Math.min(viewWidth,
+            (int) (mThumbnailRect.width() * mThumbnailScale));
+        final int thumbnailHeight = Math.min(viewHeight,
+            (int) (mThumbnailRect.height() * mThumbnailScale));
+
+        if (mUpdateThumbnailOutline) {
+            updateThumbnailOutline();
+            mUpdateThumbnailOutline = false;
+        }
+        if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+            // Draw the background, there will be some small overdraw with the thumbnail
+            if (thumbnailWidth < viewWidth) {
+                // Portrait thumbnail on a landscape task view
+                canvas.drawPath(mRestBackgroundOutline, mBgFillPaint);
+            }
+            if (thumbnailHeight < viewHeight) {
+                // Landscape thumbnail on a portrait task view
+                canvas.drawPath(mRestBackgroundOutline, mBgFillPaint);
+            }
+            canvas.drawPath(mThumbnailOutline, mDrawPaint);
+        } else {
+            canvas.drawPath(mFullBackgroundOutline, mBgFillPaint);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index 6fc4ad7..02d1cc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -23,6 +23,8 @@
 import android.view.WindowManager;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskViewTransform;
@@ -51,6 +53,9 @@
     private float mAppAspectRatio;
     private Rect mSystemInsets = new Rect();
 
+    /** The thickness of the focused task view frame. */
+    private int mFocusedFrameThickness;
+
     /**
      * When the amount of tasks is determined, the size and position of every task view can be
      * decided. Each instance of TaskGridRectInfo store the task view information for a certain
@@ -60,6 +65,8 @@
         Rect size;
         int[] xOffsets;
         int[] yOffsets;
+        int tasksPerLine;
+        int lines;
 
         TaskGridRectInfo(int taskCount) {
             size = new Rect();
@@ -68,10 +75,10 @@
 
             int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount);
 
-            int tasksPerLine = layoutTaskCount < 2 ? 1 : (
+            tasksPerLine = layoutTaskCount < 2 ? 1 : (
                 layoutTaskCount < 5 ? 2 : (
                     layoutTaskCount < 7 ? 3 : 4));
-            int lines = layoutTaskCount < 3 ? 1 : 2;
+            lines = layoutTaskCount < 3 ? 1 : 2;
 
             // A couple of special cases.
             boolean landscapeWindow = mWindowRect.width() > mWindowRect.height();
@@ -98,11 +105,13 @@
             if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) {
                 // Width bound.
                 taskWidth = maxTaskWidth;
-                taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight);
+                // Here we should round the height to the nearest integer.
+                taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight + 0.5);
             } else {
                 // Height bound.
                 taskHeight = maxTaskHeight;
-                taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio);
+                // Here we should round the width to the nearest integer.
+                taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio + 0.5);
             }
             size.set(0, 0, taskWidth, taskHeight);
 
@@ -137,6 +146,9 @@
     public void reloadOnConfigurationChange(Context context) {
         Resources res = context.getResources();
         mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view);
+        mFocusedFrameThickness = res.getDimensionPixelSize(
+            R.dimen.recents_grid_task_view_focused_frame_thickness);
+
         mTaskGridRect = new Rect();
         mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height);
 
@@ -159,6 +171,10 @@
      */
     public TaskViewTransform getTransform(int taskIndex, int taskCount,
         TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
+        if (taskCount == 0) {
+            transformOut.reset();
+            return transformOut;
+        }
 
         TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1];
         mTaskGridRect.set(gridInfo.size);
@@ -174,7 +190,7 @@
 
         // We also need to invert the index in order to display the most recent tasks first.
         int taskLayoutIndex = taskCount - taskIndex - 1;
-        boolean isTaskViewVisible = (taskLayoutIndex < MAX_LAYOUT_TASK_COUNT);
+        boolean isTaskViewVisible = taskLayoutIndex < MAX_LAYOUT_TASK_COUNT;
 
         // Fill out the transform
         transformOut.scale = 1f;
@@ -190,6 +206,48 @@
         return transformOut;
     }
 
+    /**
+     * Return the proper task index to focus for arrow key navigation.
+     * @param taskCount             The amount of tasks.
+     * @param currentFocusedIndex   The index of the currently focused task.
+     * @param direction             The direction we're navigating.
+     * @return  The index of the task that should get the focus.
+     */
+    public int navigateFocus(int taskCount, int currentFocusedIndex, Direction direction) {
+        if (taskCount < 1 || taskCount > MAX_LAYOUT_TASK_COUNT) {
+            return -1;
+        }
+        if (currentFocusedIndex == -1) {
+            return 0;
+        }
+        int newIndex = currentFocusedIndex;
+        final TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1];
+        final int currentLine = (taskCount - 1 - currentFocusedIndex) / gridInfo.tasksPerLine;
+        switch (direction) {
+            case UP:
+                newIndex += gridInfo.tasksPerLine;
+                newIndex = newIndex >= taskCount ? currentFocusedIndex : newIndex;
+                break;
+            case DOWN:
+                newIndex -= gridInfo.tasksPerLine;
+                newIndex = newIndex < 0 ? currentFocusedIndex : newIndex;
+                break;
+            case LEFT:
+                newIndex++;
+                final int leftMostIndex = (taskCount - 1) - currentLine * gridInfo.tasksPerLine;
+                newIndex = newIndex > leftMostIndex ? currentFocusedIndex : newIndex;
+                break;
+            case RIGHT:
+                newIndex--;
+                int rightMostIndex =
+                    (taskCount - 1) - (currentLine + 1) * gridInfo.tasksPerLine + 1;
+                rightMostIndex = rightMostIndex < 0 ? 0 : rightMostIndex;
+                newIndex = newIndex < rightMostIndex ? currentFocusedIndex : newIndex;
+                break;
+        }
+        return newIndex;
+    }
+
     public void initialize(Rect windowRect) {
         mWindowRect = windowRect;
         // Define paddings in terms of percentage of the total area.
@@ -223,7 +281,18 @@
         return buttonRect;
     }
 
+    public void updateTaskGridRect(int taskCount) {
+        if (taskCount > 0) {
+            TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1];
+            mTaskGridRect.set(gridInfo.size);
+        }
+    }
+
     public Rect getTaskGridRect() {
         return mTaskGridRect;
     }
+
+    public int getFocusFrameThickness() {
+        return mFocusedFrameThickness;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
new file mode 100644
index 0000000..86ed583
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views.grid;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import com.android.systemui.R;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.TaskStackView;
+
+public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListener {
+
+    private TaskStackView mSv;
+    private TaskGridLayoutAlgorithm mTaskGridLayoutAlgorithm;
+    public TaskViewFocusFrame(Context context) {
+        this(context, null);
+    }
+
+    public TaskViewFocusFrame(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskViewFocusFrame(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TaskViewFocusFrame(Context context, AttributeSet attrs, int defStyleAttr,
+        int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setBackground(mContext.getDrawable(
+            R.drawable.recents_grid_task_view_focus_frame_background));
+        setFocusable(false);
+        hide();
+    }
+
+    public TaskViewFocusFrame(Context context, TaskStackView stackView,
+        TaskGridLayoutAlgorithm taskGridLayoutAlgorithm) {
+        this(context);
+        mSv = stackView;
+        mTaskGridLayoutAlgorithm = taskGridLayoutAlgorithm;
+    }
+
+    /**
+     * Measure the width and height of the focus frame according to the current grid task view size.
+     */
+    public void measure() {
+        int thickness = mTaskGridLayoutAlgorithm.getFocusFrameThickness();
+        Rect rect = mTaskGridLayoutAlgorithm.getTaskGridRect();
+        measure(
+            MeasureSpec.makeMeasureSpec(rect.width() + thickness * 2, MeasureSpec.EXACTLY),
+            MeasureSpec.makeMeasureSpec(rect.height() + thickness * 2, MeasureSpec.EXACTLY));
+    }
+
+    /**
+     * Layout the focus frame with its size.
+     */
+    public void layout() {
+        layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+    }
+
+    /**
+     * Update the current size of grid task view and the focus frame.
+     */
+    public void resize() {
+        if (mSv.useGridLayout()) {
+            mTaskGridLayoutAlgorithm.updateTaskGridRect(mSv.getStack().getTaskCount());
+            measure();
+            requestLayout();
+        }
+    }
+
+    /**
+     * Move the task view focus frame to surround the newly focused view. If it's {@code null} or
+     * it's not an instance of GridTaskView, we hide the focus frame.
+     * @param newFocus The newly focused view.
+     */
+    public void moveGridTaskViewFocus(View newFocus) {
+        if (mSv.useGridLayout()) {
+            // The frame only shows up in the grid layout. It shouldn't show up in the stack
+            // layout including when we're in the split screen.
+            if (newFocus instanceof GridTaskView) {
+                // If the focus goes to a GridTaskView, we show the frame and layout it.
+                int[] location = new int[2];
+                newFocus.getLocationInWindow(location);
+                int thickness = mTaskGridLayoutAlgorithm.getFocusFrameThickness();
+                setTranslationX(location[0] - thickness);
+                setTranslationY(location[1] - thickness);
+                show();
+            } else {
+                // If focus goes to other views, we hide the frame.
+                hide();
+            }
+        }
+    }
+
+    @Override
+    public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+        if (!mSv.useGridLayout()) {
+            return;
+        }
+        if (newFocus == null) {
+            // We're going to touch mode, unset the focus.
+            moveGridTaskViewFocus(null);
+            return;
+        }
+        if (oldFocus == null) {
+            // We're returning from touch mode, set the focus to the previously focused task.
+            final TaskStack stack = mSv.getStack();
+            final int taskCount = stack.getTaskCount();
+            final int k = stack.indexOfStackTask(mSv.getFocusedTask());
+            final int taskIndexToFocus = k == -1 ? (taskCount - 1) : (k % taskCount);
+            mSv.setFocusedTask(taskIndexToFocus, false, true);
+        }
+    }
+
+    private void show() {
+        setAlpha(1f);
+    }
+
+    private void hide() {
+        setAlpha(0f);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index 3059a05..7825e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -37,6 +37,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
 
 import java.util.ArrayList;
 
@@ -70,7 +71,7 @@
     private final CurrentUserTracker mUserTracker;
     private final IVrManager mVrManager;
 
-    private Handler mBackgroundHandler;
+    private final Handler mBackgroundHandler;
     private final BrightnessObserver mBrightnessObserver;
 
     private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
@@ -276,7 +277,7 @@
         mContext = context;
         mIcon = icon;
         mControl = control;
-        mBackgroundHandler = new Handler(Looper.getMainLooper());
+        mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
         mUserTracker = new CurrentUserTracker(mContext) {
             @Override
             public void onUserSwitched(int newUserId) {
@@ -298,10 +299,6 @@
         mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
     }
 
-    public void setBackgroundLooper(Looper backgroundLooper) {
-        mBackgroundHandler = new Handler(backgroundLooper);
-    }
-
     public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
         mChangeCallbacks.add(cb);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index d1ab96d..b5358bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -182,6 +182,7 @@
     private int mStartTint;
     private int mOverrideTint;
     private float mOverrideAmount;
+    private boolean mShadowHidden;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -210,6 +211,7 @@
         super.onFinishInflate();
         mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
         mFakeShadow = (FakeShadowView) findViewById(R.id.fake_shadow);
+        mShadowHidden = mFakeShadow.getVisibility() != VISIBLE;
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
         mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
         mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
@@ -249,7 +251,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         boolean result;
-        if (mDimmed && !isTouchExplorationEnabled()) {
+        if (mDimmed && !isTouchExplorationEnabled() && isInteractive()) {
             boolean wasActivated = mActivated;
             result = handleTouchEventDimmed(event);
             if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
@@ -261,6 +263,13 @@
         return result;
     }
 
+    /**
+     * @return whether this view is interactive and can be double tapped
+     */
+    protected boolean isInteractive() {
+        return true;
+    }
+
     @Override
     public void drawableHotspotChanged(float x, float y) {
         if (!mDimmed){
@@ -1020,9 +1029,13 @@
     @Override
     public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
             int outlineTranslation) {
-        mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
-                + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
-                outlineTranslation);
+        boolean hiddenBefore = mShadowHidden;
+        mShadowHidden = shadowIntensity == 0.0f;
+        if (!mShadowHidden || !hiddenBefore) {
+            mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
+                            + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
+                    outlineTranslation);
+        }
     }
 
     public int getBackgroundColorWithoutTint() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 561b469..6ac5cb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -71,7 +71,6 @@
 import android.view.Display;
 import android.view.IWindowManager;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
@@ -92,6 +91,7 @@
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
@@ -100,11 +100,11 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.NotificationGuts.OnGutsClosedListener;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.NavigationBarView;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -122,7 +122,7 @@
 public abstract class BaseStatusBar extends SystemUI implements
         CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
         ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
-        ExpandableNotificationRow.OnExpandClickListener, OnGutsClosedListener {
+        ExpandableNotificationRow.OnExpandClickListener {
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
@@ -223,6 +223,7 @@
 
     protected KeyguardManager mKeyguardManager;
     private LockPatternUtils mLockPatternUtils;
+    private DeviceProvisionedController mDeviceProvisionedController;
 
     // UI-specific methods
 
@@ -237,8 +238,6 @@
 
     protected Display mDisplay;
 
-    private boolean mDeviceProvisioned = false;
-
     protected RecentsComponent mRecents;
 
     protected int mZenMode;
@@ -270,7 +269,7 @@
 
     @Override  // NotificationData.Environment
     public boolean isDeviceProvisioned() {
-        return mDeviceProvisioned;
+        return mDeviceProvisionedController.isDeviceProvisioned();
     }
 
     private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@@ -284,15 +283,17 @@
         return mVrMode;
     }
 
+    private final DeviceProvisionedListener mDeviceProvisionedListener =
+            new DeviceProvisionedListener() {
+        @Override
+        public void onDeviceProvisionedChanged() {
+            updateNotifications();
+        }
+    };
+
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
         public void onChange(boolean selfChange) {
-            final boolean provisioned = 0 != Settings.Global.getInt(
-                    mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0);
-            if (provisioned != mDeviceProvisioned) {
-                mDeviceProvisioned = provisioned;
-                updateNotifications();
-            }
             final int mode = Settings.Global.getInt(mContext.getContentResolver(),
                     Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
             setZenMode(mode);
@@ -707,9 +708,8 @@
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
-                mSettingsObserver);
+        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
                 mSettingsObserver);
@@ -1041,7 +1041,12 @@
         PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
         row.setTag(sbn.getPackageName());
         final NotificationGuts guts = row.getGuts();
-        guts.setClosedListener(this);
+        guts.setClosedListener((NotificationGuts g) -> {
+            if (!row.isRemoved()) {
+                mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
+            }
+            mNotificationGutsExposed = null;
+        });
 
         final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -1127,6 +1132,11 @@
                 // Post to ensure the the guts are properly laid out.
                 guts.post(new Runnable() {
                     public void run() {
+                        if (row.getWindowToken() == null) {
+                            Log.e(TAG, "Trying to show notification guts, but not attached to "
+                                    + "window");
+                            return;
+                        }
                         dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
                                 false /* animate */);
                         guts.setVisibility(View.VISIBLE);
@@ -1149,7 +1159,7 @@
                         guts.setExposed(true /* exposed */,
                                 mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
                         row.closeRemoteInput();
-                        mStackScroller.onHeightChanged(null, true /* needsAnimation */);
+                        mStackScroller.onHeightChanged(row, true /* needsAnimation */);
                         mNotificationGutsExposed = guts;
                     }
                 });
@@ -1183,12 +1193,6 @@
     }
 
     @Override
-    public void onGutsClosed(NotificationGuts guts) {
-        mStackScroller.onHeightChanged(null, true /* needsAnimation */);
-        mNotificationGutsExposed = null;
-    }
-
-    @Override
     public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
         int msg = MSG_SHOW_RECENT_APPS;
         mHandler.removeMessages(msg);
@@ -1520,6 +1524,7 @@
         final RemoteViews bigContentView = entry.cachedBigContentView;
         final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
         final RemoteViews publicContentView = entry.cachedPublicContentView;
+        final RemoteViews ambientContentView = entry.cachedAmbientContentView;
 
         if (contentView == null) {
             Log.v(TAG, "no contentView for: " + sbn.getNotification());
@@ -1600,6 +1605,7 @@
         View bigContentViewLocal = null;
         View headsUpContentViewLocal = null;
         View publicViewLocal = null;
+        View ambientViewLocal = null;
         try {
             contentViewLocal = contentView.apply(
                     sbn.getPackageContext(mContext),
@@ -1622,6 +1628,11 @@
                         sbn.getPackageContext(mContext),
                         contentContainerPublic, mOnClickHandler);
             }
+            if (ambientContentView != null) {
+                ambientViewLocal = ambientContentView.apply(
+                        sbn.getPackageContext(mContext),
+                        contentContainer, mOnClickHandler);
+            }
 
             if (contentViewLocal != null) {
                 contentViewLocal.setIsRootNamespace(true);
@@ -1639,6 +1650,11 @@
                 publicViewLocal.setIsRootNamespace(true);
                 contentContainerPublic.setContractedChild(publicViewLocal);
             }
+
+            if (ambientViewLocal != null) {
+                ambientViewLocal.setIsRootNamespace(true);
+                contentContainer.setAmbientChild(ambientViewLocal);
+            }
         }
         catch (RuntimeException e) {
             final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
@@ -2135,6 +2151,7 @@
                 row.setOnKeyguard(false);
                 row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
             }
+            entry.row.setShowAmbient(isDozing());
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.row.isRemoved();
@@ -2172,6 +2189,10 @@
         mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
     }
 
+    public boolean isDozing() {
+        return false;
+    }
+
     public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
         return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
     }
@@ -2384,7 +2405,7 @@
             Log.d(TAG, "failed to query dream manager", e);
         }
 
-        if (!inUse) {
+        if (!inUse && !isDozing()) {
             if (DEBUG) {
                 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
             }
@@ -2449,6 +2470,7 @@
         } catch (RemoteException e) {
             // Ignore.
         }
+        mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index fed28e3..477701c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -185,7 +185,14 @@
     public void animateCollapsePanels() {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_COLLAPSE_PANELS);
-            mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS);
+            mHandler.obtainMessage(MSG_COLLAPSE_PANELS, 0, 0).sendToTarget();
+        }
+    }
+
+    public void animateCollapsePanels(int flags) {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_COLLAPSE_PANELS);
+            mHandler.obtainMessage(MSG_COLLAPSE_PANELS, flags, 0).sendToTarget();
         }
     }
 
@@ -450,7 +457,7 @@
                     break;
                 case MSG_COLLAPSE_PANELS:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).animateCollapsePanels(0);
+                        mCallbacks.get(i).animateCollapsePanels(msg.arg1);
                     }
                     break;
                 case MSG_EXPAND_SETTINGS:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 173a110..93c48f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -74,6 +74,7 @@
     private int mMaxHeadsUpHeight;
     private int mNotificationMinHeight;
     private int mNotificationMaxHeight;
+    private int mNotificationAmbientHeight;
     private int mIncreasedPaddingBetweenElements;
 
     /** Does this row contain layouts that can adapt to row expansion */
@@ -197,6 +198,7 @@
     private float mContentTransformationAmount;
     private boolean mIconsVisible = true;
     private boolean mAboveShelf;
+    private boolean mShowAmbient;
     private boolean mIsLastChild;
     private Runnable mOnDismissRunnable;
 
@@ -326,7 +328,8 @@
                         != com.android.internal.R.id.status_bar_latest_event_content;
         int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
                 : mMaxHeadsUpHeight;
-        layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+        layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
+                mNotificationAmbientHeight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -954,6 +957,7 @@
         mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
         mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
         mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
+        mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
         mMaxHeadsUpHeightLegacy = getFontScaledHeight(
                 R.dimen.notification_max_heads_up_height_legacy);
         mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
@@ -1353,6 +1357,8 @@
             return mGuts.getHeight();
         } else if ((isChildInGroup() && !isGroupExpanded())) {
             return mPrivateLayout.getMinHeight();
+        } else if (mShowAmbient) {
+            return getAmbientHeight();
         } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
             return getMinHeight();
         } else if (mIsSummaryWithChildren && !mOnKeyguard) {
@@ -1683,6 +1689,13 @@
         return showingLayout.getMinHeight();
     }
 
+    private int getAmbientHeight() {
+        NotificationContentView showingLayout = getShowingLayout();
+        return showingLayout.getAmbientChild() != null
+                ? showingLayout.getAmbientChild().getHeight()
+                : getCollapsedHeight();
+    }
+
     @Override
     public int getCollapsedHeight() {
         if (mIsSummaryWithChildren && !mShowingPublic) {
@@ -1879,6 +1892,13 @@
         return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
     }
 
+    public void setShowAmbient(boolean showAmbient) {
+        if (showAmbient != mShowAmbient) {
+            mShowAmbient = showAmbient;
+            notifyHeightChanged(false /* needsAnimation */);
+        }
+    }
+
     public void setAboveShelf(boolean aboveShelf) {
         mAboveShelf = aboveShelf;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index f451aef..08fd93d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -42,10 +42,10 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
 import com.android.systemui.statusbar.phone.LockIcon;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 
 /**
@@ -109,7 +109,7 @@
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
         context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
                 new IntentFilter(Intent.ACTION_TIME_TICK), null,
-                PhoneStatusBar.getTimeTickHandler(mContext));
+                Dependency.get(Dependency.TIME_TICK_HANDLER));
 
         updateDisclosure();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index ad6a5db..b45cde8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -31,6 +31,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
@@ -52,6 +53,7 @@
     private static final int VISIBLE_TYPE_EXPANDED = 1;
     private static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
+    private static final int VISIBLE_TYPE_AMBIENT = 4;
     public static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
@@ -62,6 +64,7 @@
     private View mExpandedChild;
     private View mHeadsUpChild;
     private HybridNotificationView mSingleLineView;
+    private View mAmbientChild;
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
@@ -69,6 +72,7 @@
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
     private NotificationViewWrapper mHeadsUpWrapper;
+    private NotificationViewWrapper mAmbientWrapper;
     private HybridGroupManager mHybridGroupManager;
     private int mClipTopAmount;
     private int mContentHeight;
@@ -81,6 +85,7 @@
     private int mSmallHeight;
     private int mHeadsUpHeight;
     private int mNotificationMaxHeight;
+    private int mNotificationAmbientHeight;
     private StatusBarNotification mStatusBarNotification;
     private NotificationGroupManager mGroupManager;
     private RemoteInputController mRemoteInputController;
@@ -136,10 +141,12 @@
         reset();
     }
 
-    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
+    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
+            int ambientHeight) {
         mSmallHeight = smallHeight;
         mHeadsUpHeight = headsUpMaxHeight;
         mNotificationMaxHeight = maxHeight;
+        mNotificationAmbientHeight = ambientHeight;
     }
 
     @Override
@@ -215,6 +222,17 @@
                     MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
         }
+        if (mAmbientChild != null) {
+            int size = Math.min(maxSize, mNotificationAmbientHeight);
+            ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
+            if (layoutParams.height >= 0) {
+                // An actual height is set
+                size = Math.min(size, layoutParams.height);
+            }
+            mAmbientChild.measure(widthMeasureSpec,
+                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+            maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
+        }
         int ownHeight = Math.min(maxChildHeight, maxSize);
         setMeasuredDimension(width, ownHeight);
     }
@@ -293,10 +311,6 @@
     }
 
     public void reset() {
-        if (mContractedChild != null) {
-            mContractedChild.animate().cancel();
-            removeView(mContractedChild);
-        }
         mPreviousExpandedRemoteInputIntent = null;
         if (mExpandedRemoteInput != null) {
             mExpandedRemoteInput.onNotificationUpdateOrReset();
@@ -327,7 +341,6 @@
             removeView(mHeadsUpChild);
             mHeadsUpRemoteInput = null;
         }
-        mContractedChild = null;
         mExpandedChild = null;
         mHeadsUpChild = null;
     }
@@ -344,6 +357,10 @@
         return mHeadsUpChild;
     }
 
+    public View getAmbientChild() {
+        return mAmbientChild;
+    }
+
     public void setContractedChild(View child) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
@@ -378,6 +395,17 @@
                 mContainingNotification);
     }
 
+    public void setAmbientChild(View child) {
+        if (mAmbientChild != null) {
+            mAmbientChild.animate().cancel();
+            removeView(mAmbientChild);
+        }
+        addView(child);
+        mAmbientChild = child;
+        mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child,
+                mContainingNotification);
+    }
+
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -452,6 +480,11 @@
                         com.android.internal.R.dimen.notification_action_list_height);
         }
 
+        if (isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
+            return mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.notification_action_list_height);
+        }
+
         // Transition between heads-up & expanded, or pinned.
         if (mHeadsUpChild != null && mExpandedChild != null) {
             boolean transitioningBetweenHunAndExpanded =
@@ -656,39 +689,26 @@
     }
 
     private void forceUpdateVisibilities() {
-        boolean contractedVisible = mVisibleType == VISIBLE_TYPE_CONTRACTED
-                || mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED;
-        boolean expandedVisible = mVisibleType == VISIBLE_TYPE_EXPANDED
-                || mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED;
-        boolean headsUpVisible = mVisibleType == VISIBLE_TYPE_HEADSUP
-                || mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP;
-        boolean singleLineVisible = mVisibleType == VISIBLE_TYPE_SINGLELINE
-                || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE;
-        if (!contractedVisible) {
-            mContractedChild.setVisibility(View.INVISIBLE);
+        forceUpdateVisibility(VISIBLE_TYPE_CONTRACTED, mContractedChild, mContractedWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_EXPANDED, mExpandedChild, mExpandedWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
+        forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
+        // forceUpdateVisibilities cancels outstanding animations without updating the
+        // mAnimationStartVisibleType. Do so here instead.
+        mAnimationStartVisibleType = UNDEFINED;
+    }
+
+    private void forceUpdateVisibility(int type, View view, TransformableView wrapper) {
+        if (view == null) {
+            return;
+        }
+        boolean visible = mVisibleType == type
+                || mTransformationStartVisibleType == type;
+        if (!visible) {
+            view.setVisibility(INVISIBLE);
         } else {
-            mContractedWrapper.setVisible(true);
-        }
-        if (mExpandedChild != null) {
-            if (!expandedVisible) {
-                mExpandedChild.setVisibility(View.INVISIBLE);
-            } else {
-                mExpandedWrapper.setVisible(true);
-            }
-        }
-        if (mHeadsUpChild != null) {
-            if (!headsUpVisible) {
-                mHeadsUpChild.setVisibility(View.INVISIBLE);
-            } else {
-                mHeadsUpWrapper.setVisible(true);
-            }
-        }
-        if (mSingleLineView != null) {
-            if (!singleLineVisible) {
-                mSingleLineView.setVisibility(View.INVISIBLE);
-            } else {
-                mSingleLineView.setVisible(true);
-            }
+            wrapper.setVisible(true);
         }
     }
 
@@ -722,19 +742,25 @@
     }
 
     private void updateViewVisibilities(int visibleType) {
-        boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
-        mContractedWrapper.setVisible(contractedVisible);
-        if (mExpandedChild != null) {
-            boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
-            mExpandedWrapper.setVisible(expandedVisible);
-        }
-        if (mHeadsUpChild != null) {
-            boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
-            mHeadsUpWrapper.setVisible(headsUpVisible);
-        }
-        if (mSingleLineView != null) {
-            boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
-            mSingleLineView.setVisible(singleLineVisible);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_CONTRACTED,
+                mContractedChild, mContractedWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_EXPANDED,
+                mExpandedChild, mExpandedWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_HEADSUP,
+                mHeadsUpChild, mHeadsUpWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_SINGLELINE,
+                mSingleLineView, mSingleLineView);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
+                mAmbientChild, mAmbientWrapper);
+        // updateViewVisibilities cancels outstanding animations without updating the
+        // mAnimationStartVisibleType. Do so here instead.
+        mAnimationStartVisibleType = UNDEFINED;
+    }
+
+    private void updateViewVisibility(int visibleType, int type, View view,
+            TransformableView wrapper) {
+        if (view != null) {
+            wrapper.setVisible(visibleType == type);
         }
     }
 
@@ -784,6 +810,8 @@
                 return mHeadsUpWrapper;
             case VISIBLE_TYPE_SINGLELINE:
                 return mSingleLineView;
+            case VISIBLE_TYPE_AMBIENT:
+                return mAmbientWrapper;
             default:
                 return mContractedWrapper;
         }
@@ -801,6 +829,8 @@
                 return mHeadsUpChild;
             case VISIBLE_TYPE_SINGLELINE:
                 return mSingleLineView;
+            case VISIBLE_TYPE_AMBIENT:
+                return mAmbientChild;
             default:
                 return mContractedChild;
         }
@@ -814,6 +844,8 @@
                 return mHeadsUpWrapper;
             case VISIBLE_TYPE_CONTRACTED:
                 return mContractedWrapper;
+            case VISIBLE_TYPE_AMBIENT:
+                return mAmbientWrapper;
             default:
                 return null;
         }
@@ -823,6 +855,10 @@
      * @return one of the static enum types in this view, calculated form the current state
      */
     public int calculateVisibleType() {
+        if (mDark && !mIsChildInGroup) {
+            // TODO: Handle notification groups
+            return VISIBLE_TYPE_AMBIENT;
+        }
         if (mUserExpanding) {
             int height = !mIsChildInGroup || isGroupExpanded()
                     || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
@@ -895,6 +931,7 @@
         if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
             mSingleLineView.setDark(dark, fade, delay);
         }
+        selectLayout(!dark && fade /* animate */, false /* force */);
     }
 
     public void setHeadsUp(boolean headsUp) {
@@ -947,6 +984,9 @@
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.notifyContentUpdated(entry.notification);
         }
+        if (mAmbientChild != null) {
+            mAmbientWrapper.notifyContentUpdated(entry.notification);
+        }
         updateShowingLegacyBackground();
         mForceSelectNextLayout = true;
         setDark(mDark, false /* animate */, 0 /* delay */);
@@ -1133,6 +1173,9 @@
         if (header == null && mHeadsUpChild != null) {
             header = mHeadsUpWrapper.getNotificationHeader();
         }
+        if (header == null && mAmbientChild != null) {
+            header = mAmbientWrapper.getNotificationHeader();
+        }
         return header;
     }
 
@@ -1200,6 +1243,11 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isAnimatingVisibleType() {
+        return mAnimationStartVisibleType != UNDEFINED;
+    }
+
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         mHeadsUpAnimatingAway = headsUpAnimatingAway;
         selectLayout(false /* animate */, true /* force */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c06e639..458daf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -67,6 +67,7 @@
         public RemoteViews cachedBigContentView;
         public RemoteViews cachedHeadsUpContentView;
         public RemoteViews cachedPublicContentView;
+        public RemoteViews cachedAmbientContentView;
         public CharSequence remoteInputText;
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
@@ -126,6 +127,8 @@
                         updatedNotificationBuilder.createHeadsUpContentView();
                 final RemoteViews newPublicNotification
                         = updatedNotificationBuilder.makePublicContentView();
+                final RemoteViews newAmbientNotification
+                        = updatedNotificationBuilder.makeAmbientNotification();
 
                 boolean sameCustomView = Objects.equals(
                         notification.getNotification().extras.getBoolean(
@@ -136,11 +139,13 @@
                         && compareRemoteViews(cachedBigContentView, newBigContentView)
                         && compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
                         && compareRemoteViews(cachedPublicContentView, newPublicNotification)
+                        && compareRemoteViews(cachedAmbientContentView, newAmbientNotification)
                         && sameCustomView;
                 cachedPublicContentView = newPublicNotification;
                 cachedHeadsUpContentView = newHeadsUpContentView;
                 cachedBigContentView = newBigContentView;
                 cachedContentView = newContentView;
+                cachedAmbientContentView = newAmbientNotification;
             } else {
                 final Notification.Builder builder
                         = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
@@ -149,6 +154,7 @@
                 cachedBigContentView = builder.createBigContentView();
                 cachedHeadsUpContentView = builder.createHeadsUpContentView();
                 cachedPublicContentView = builder.makePublicContentView();
+                cachedAmbientContentView = builder.makeAmbientNotification();
 
                 applyInPlace = false;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index bc1b9fb..e8e9d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -67,6 +67,7 @@
     private int mStatusBarState;
     private float mMaxShelfEnd;
     private int mRelativeOffset;
+    private boolean mInteractive;
 
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -128,6 +129,7 @@
         } else {
             mViewInvertHelper.update(dark);
         }
+        mShelfIcons.setAmbient(dark);
     }
 
     @Override
@@ -555,13 +557,18 @@
     }
 
     private void updateInteractiveness() {
-        boolean interactive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf;
-        setClickable(interactive);
-        setFocusable(interactive);
-        setImportantForAccessibility(interactive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+        mInteractive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf;
+        setClickable(mInteractive);
+        setFocusable(mInteractive);
+        setImportantForAccessibility(mInteractive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
                 : View.IMPORTANT_FOR_ACCESSIBILITY_NO);
     }
 
+    @Override
+    protected boolean isInteractive() {
+        return mInteractive;
+    }
+
     public void setMaxShelfEnd(float maxShelfEnd) {
         mMaxShelfEnd = maxShelfEnd;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 68d5cd4..1128101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -37,8 +37,10 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityController;
@@ -62,8 +64,8 @@
     private static final String SLOT_WIFI = "wifi";
     private static final String SLOT_ETHERNET = "ethernet";
 
-    NetworkControllerImpl mNC;
-    SecurityController mSC;
+    private final NetworkController mNetworkController;
+    private final SecurityController mSecurityController;
 
     private boolean mNoSimsVisible = false;
     private boolean mVpnVisible = false;
@@ -131,6 +133,8 @@
         TypedValue typedValue = new TypedValue();
         res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
         mIconScaleFactor = typedValue.getFloat();
+        mNetworkController = Dependency.get(NetworkController.class);
+        mSecurityController = Dependency.get(SecurityController.class);
     }
 
     @Override
@@ -151,24 +155,11 @@
             mBlockEthernet = blockEthernet;
             mBlockWifi = blockWifi;
             // Re-register to get new callbacks.
-            mNC.removeCallback(this);
-            mNC.addCallback(this);
+            mNetworkController.removeCallback(this);
+            mNetworkController.addCallback(this);
         }
     }
 
-    public void setNetworkController(NetworkControllerImpl nc) {
-        if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
-        mNC = nc;
-    }
-
-    public void setSecurityController(SecurityController sc) {
-        if (DEBUG) Log.d(TAG, "SecurityController=" + sc);
-        mSC = sc;
-        mSC.addCallback(this);
-        mVpnVisible = mSC.isVpnEnabled();
-        mVpnIconId = currentVpnIconId(mSC.isVpnBranded());
-    }
-
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -212,9 +203,13 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
+        mVpnVisible = mSecurityController.isVpnEnabled();
+        mVpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
 
         for (PhoneState state : mPhoneStates) {
-            mMobileSignalGroup.addView(state.mMobileGroup);
+            if (state.mMobileGroup.getParent() == null) {
+                mMobileSignalGroup.addView(state.mMobileGroup);
+            }
         }
 
         int endPadding = mMobileSignalGroup.getChildCount() > 0 ? mMobileSignalGroupEndPadding : 0;
@@ -224,15 +219,16 @@
 
         apply();
         applyIconTint();
-        mNC.addCallback(this);
+        mNetworkController.addCallback(this);
+        mSecurityController.addCallback(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         mMobileSignalGroup.removeAllViews();
         TunerService.get(mContext).removeTunable(this);
-        mSC.removeCallback(this);
-        mNC.removeCallback(this);
+        mSecurityController.removeCallback(this);
+        mNetworkController.removeCallback(this);
 
         super.onDetachedFromWindow();
     }
@@ -251,8 +247,8 @@
         post(new Runnable() {
             @Override
             public void run() {
-                mVpnVisible = mSC.isVpnEnabled();
-                mVpnIconId = currentVpnIconId(mSC.isVpnBranded());
+                mVpnVisible = mSecurityController.isVpnEnabled();
+                mVpnIconId = currentVpnIconId(mSecurityController.isVpnBranded());
                 apply();
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index a2c2fd7..399b0d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -221,6 +221,8 @@
         setContentDescription(icon.contentDescription);
         if (!iconEquals) {
             if (!updateDrawable(false /* no clear */)) return false;
+            // we have to clear the grayscale tag since it may have changed
+            setTag(R.id.icon_is_grayscale, null);
         }
         if (!levelEquals) {
             setImageLevel(icon.iconLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 1c8c317..3bbda4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -30,7 +30,7 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.ActivityStarter;
 
 import java.net.URISyntaxException;
 import java.util.ArrayList;
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 7adb36d..f24e40b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -24,8 +24,6 @@
 import android.content.IntentFilter;
 import android.graphics.PixelFormat;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
@@ -35,15 +33,16 @@
 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.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.PhoneStatusBar;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 /**
  * A status bar (and navigation bar) tailored for the automotive use case.
@@ -73,6 +72,7 @@
         SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
         registerPackageChangeReceivers();
 
+        createBatteryController();
         mCarBatteryController.startListening();
         mConnectedDeviceSignalController.startListening();
     }
@@ -105,7 +105,7 @@
                         R.dimen.status_bar_connected_device_signal_margin_end));
 
         mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
-                mSignalsView, mBluetoothController);
+                mSignalsView);
 
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
@@ -114,8 +114,7 @@
         return statusBarView;
     }
 
-    @Override
-    protected BatteryController createBatteryController() {
+    private BatteryController createBatteryController() {
         mCarBatteryController = new CarBatteryController(mContext);
         mCarBatteryController.addBatteryViewHandler(this);
         return mCarBatteryController;
@@ -211,8 +210,11 @@
 
     @Override
     protected void createUserSwitcher() {
-        if (mUserSwitcherController.useFullscreenUserSwitcher()) {
-            mFullscreenUserSwitcher = new FullscreenUserSwitcher(this, mUserSwitcherController,
+        UserSwitcherController userSwitcherController =
+                Dependency.get(UserSwitcherController.class);
+        if (userSwitcherController.useFullscreenUserSwitcher()) {
+            mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
+                    userSwitcherController,
                     (ViewStub) mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
         } else {
             super.createUserSwitcher();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
index a3e1b3a..c308930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/ConnectedDeviceSignalController.java
@@ -15,6 +15,7 @@
 import android.util.TypedValue;
 import android.view.View;
 import android.widget.ImageView;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ScalingDrawableWrapper;
 import com.android.systemui.statusbar.policy.BluetoothController;
@@ -67,10 +68,9 @@
 
     private BluetoothHeadsetClient mBluetoothHeadsetClient;
 
-    public ConnectedDeviceSignalController(Context context, View signalsView,
-            BluetoothController controller) {
+    public ConnectedDeviceSignalController(Context context, View signalsView) {
         mContext = context;
-        mController = controller;
+        mController = Dependency.get(BluetoothController.class);
 
         mSignalsView = signalsView;
         mNetworkSignalView = (ImageView)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 7ca2df9..b984c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -116,8 +116,10 @@
 
     private void resolveTemplateViews(StatusBarNotification notification) {
         mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
-        mPicture.setTag(ImageTransformState.ICON_TAG,
-                notification.getNotification().getLargeIcon());
+        if (mPicture != null) {
+            mPicture.setTag(ImageTransformState.ICON_TAG,
+                    notification.getNotification().getLargeIcon());
+        }
         mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
         mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
         final View progress = mView.findViewById(com.android.internal.R.id.progress);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 5047041..a4e5916 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -39,6 +39,7 @@
     private VisibilityLocationProvider mVisibilityLocationProvider;
     private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
     private ArraySet<View> mAddedChildren = new ArraySet<>();
+    private boolean mPulsing;
 
     /**
      * Add a callback to invoke when reordering is allowed again.
@@ -67,8 +68,16 @@
         updateReorderingAllowed();
     }
 
+    /**
+     * @param pulsing whether we are currently pulsing for ambient display.
+     */
+    public void setPulsing(boolean pulsing) {
+        mPulsing = pulsing;
+        updateReorderingAllowed();
+    }
+
     private void updateReorderingAllowed() {
-        boolean reorderingAllowed = !mScreenOn || !mPanelExpanded;
+        boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
         boolean changed = reorderingAllowed && !mReorderingAllowed;
         mReorderingAllowed = reorderingAllowed;
         if (changed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index a011162..31cfa66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -16,7 +16,10 @@
 
 import android.content.Context;
 import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings.Secure;
+
+import com.android.systemui.Dependency;
 import com.android.systemui.Prefs;
 import com.android.systemui.Prefs.Key;
 import com.android.systemui.qs.SecureSetting;
@@ -37,12 +40,12 @@
     public AutoTileManager(Context context, QSTileHost host) {
         mContext = context;
         mHost = host;
-        mHandler = new Handler(mHost.getLooper());
+        mHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
         if (!Prefs.getBoolean(context, Key.QS_HOTSPOT_ADDED, false)) {
-            host.getHotspotController().addCallback(mHotspotCallback);
+            Dependency.get(HotspotController.class).addCallback(mHotspotCallback);
         }
         if (!Prefs.getBoolean(context, Key.QS_DATA_SAVER_ADDED, false)) {
-            host.getNetworkController().getDataSaverController().addCallback(mDataSaverListener);
+            Dependency.get(DataSaverController.class).addCallback(mDataSaverListener);
         }
         if (!Prefs.getBoolean(context, Key.QS_INVERT_COLORS_ADDED, false)) {
             mColorsSetting = new SecureSetting(mContext, mHandler,
@@ -52,43 +55,33 @@
                     if (value != 0) {
                         mHost.addTile("inversion");
                         Prefs.putBoolean(mContext, Key.QS_INVERT_COLORS_ADDED, true);
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                mColorsSetting.setListening(false);
-                            }
-                        });
+                        mHandler.post(() -> mColorsSetting.setListening(false));
                     }
                 }
             };
             mColorsSetting.setListening(true);
         }
         if (!Prefs.getBoolean(context, Key.QS_WORK_ADDED, false)) {
-            host.getManagedProfileController().addCallback(mProfileCallback);
+            Dependency.get(ManagedProfileController.class).addCallback(mProfileCallback);
         }
     }
 
     public void destroy() {
         mColorsSetting.setListening(false);
-        mHost.getHotspotController().removeCallback(mHotspotCallback);
-        mHost.getNetworkController().getDataSaverController().removeCallback(mDataSaverListener);
-        mHost.getManagedProfileController().removeCallback(mProfileCallback);
+        Dependency.get(HotspotController.class).removeCallback(mHotspotCallback);
+        Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener);
+        Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback);
     }
 
     private final ManagedProfileController.Callback mProfileCallback =
             new ManagedProfileController.Callback() {
                 @Override
                 public void onManagedProfileChanged() {
-                    if (mHost.getManagedProfileController().hasActiveProfile()) {
+                    if (Dependency.get(ManagedProfileController.class).hasActiveProfile()) {
                         mHost.addTile("work");
                         Prefs.putBoolean(mContext, Key.QS_WORK_ADDED, true);
-                        mHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                mHost.getManagedProfileController().removeCallback(
-                                        mProfileCallback);
-                            }
-                        });
+                        mHandler.post(() -> Dependency.get(ManagedProfileController.class)
+                                .removeCallback(mProfileCallback));
                     }
                 }
 
@@ -105,13 +98,8 @@
             if (isDataSaving) {
                 mHost.addTile("saver");
                 Prefs.putBoolean(mContext, Key.QS_DATA_SAVER_ADDED, true);
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        mHost.getNetworkController().getDataSaverController().removeCallback(
-                                mDataSaverListener);
-                    }
-                });
+                mHandler.post(() -> Dependency.get(DataSaverController.class).removeCallback(
+                        mDataSaverListener));
             }
         }
     };
@@ -122,12 +110,8 @@
             if (enabled) {
                 mHost.addTile("hotspot");
                 Prefs.putBoolean(mContext, Key.QS_HOTSPOT_ADDED, true);
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        mHost.getHotspotController().removeCallback(mHotspotCallback);
-                    }
-                });
+                mHandler.post(() -> Dependency.get(HotspotController.class)
+                        .removeCallback(mHotspotCallback));
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 01ffe01..b78f748 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.Interpolators;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
@@ -41,7 +42,9 @@
     private final Handler mHandler = new Handler();
     private final ScrimController mScrimController;
 
+    private final Context mContext;
     private final View mStackScroller;
+    private final NotificationPanelView mNotificationPanelView;
 
     private boolean mDozing;
     private DozeHost.PulseCallback mPulseCallback;
@@ -52,10 +55,12 @@
     private float mBehindTarget;
 
     public DozeScrimController(ScrimController scrimController, Context context,
-            View stackScroller) {
+            View stackScroller, NotificationPanelView notificationPanelView) {
+        mContext = context;
         mStackScroller = stackScroller;
         mScrimController = scrimController;
         mDozeParameters = new DozeParameters(context);
+        mNotificationPanelView = notificationPanelView;
     }
 
     public void setDozing(boolean dozing, boolean animate) {
@@ -65,10 +70,7 @@
             abortAnimations();
             mScrimController.setDozeBehindAlpha(1f);
             mScrimController.setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? 0f : 1f);
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(0f);
-                mHandler.postDelayed(() -> mStackScroller.setAlpha(0f), 30);
-            }
+            mNotificationPanelView.setDark(true);
         } else {
             cancelPulsing();
             if (animate) {
@@ -83,9 +85,8 @@
                 mScrimController.setDozeBehindAlpha(0f);
                 mScrimController.setDozeInFrontAlpha(0f);
             }
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(1f);
-            }
+            // TODO: animate
+            mNotificationPanelView.setDark(false);
         }
     }
 
@@ -123,9 +124,6 @@
         if (isPulsing()) {
             final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
                     || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(1f);
-            }
             startScrimAnimation(true /* inFront */, 0f,
                     mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
                     pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
@@ -291,9 +289,6 @@
         @Override
         public void run() {
             if (DEBUG) Log.d(TAG, "Pulse out finished");
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(0f);
-            }
             DozeLog.tracePulseFinish();
 
             // Signal that the pulse is all finished so we can turn the screen off now.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index a2c106a..79120d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -58,6 +58,7 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
@@ -66,7 +67,7 @@
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton.IconState;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
-import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -230,6 +231,11 @@
         mRightAffordanceView.setOnClickListener(this);
         mLeftAffordanceView.setOnClickListener(this);
         initAccessibility();
+        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mFlashlightController = Dependency.get(FlashlightController.class);
+        mAccessibilityController = Dependency.get(AccessibilityController.class);
+        mAssistManager = Dependency.get(AssistManager.class);
+        updateLeftAffordance();
     }
 
     @Override
@@ -299,20 +305,6 @@
         mRightAffordanceView.setContentDescription(state.contentDescription);
     }
 
-    public void setActivityStarter(ActivityStarter activityStarter) {
-        mActivityStarter = activityStarter;
-    }
-
-    public void setFlashlightController(FlashlightController flashlightController) {
-        mFlashlightController = flashlightController;
-    }
-
-    public void setAccessibilityController(AccessibilityController accessibilityController) {
-        mAccessibilityController = accessibilityController;
-        mLockIcon.setAccessibilityController(accessibilityController);
-        accessibilityController.addStateChangedCallback(this);
-    }
-
     public void setPhoneStatusBar(PhoneStatusBar phoneStatusBar) {
         mPhoneStatusBar = phoneStatusBar;
         updateCameraVisibility(); // in case onFinishInflate() was called too early
@@ -761,11 +753,6 @@
         mIndicationController = keyguardIndicationController;
     }
 
-    public void setAssistManager(AssistManager assistManager) {
-        mAssistManager = assistManager;
-        updateLeftAffordance();
-    }
-
     public void updateLeftAffordance() {
         updateLeftAffordanceIcon();
         updateLeftPreview();
@@ -792,7 +779,7 @@
     private final PluginListener<IntentButtonProvider> mRightListener =
             new PluginListener<IntentButtonProvider>() {
         @Override
-        public void onPluginConnected(IntentButtonProvider plugin) {
+        public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
             setRightButton(plugin.getIntentButton());
         }
 
@@ -805,7 +792,7 @@
     private final PluginListener<IntentButtonProvider> mLeftListener =
             new PluginListener<IntentButtonProvider>() {
         @Override
-        public void onPluginConnected(IntentButtonProvider plugin) {
+        public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
             setLeftButton(plugin.getIntentButton());
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 70beac8ea..c78ec83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -68,6 +68,8 @@
     }
 
     private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
+    private int mClockBottom;
+    private boolean mDark;
 
     /**
      * Refreshes the dimension values.
@@ -86,7 +88,8 @@
     }
 
     public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
-            int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) {
+            int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount,
+            int clockBottom, boolean dark) {
         mMaxKeyguardNotifications = maxKeyguardNotifications;
         mMaxPanelHeight = maxPanelHeight;
         mExpandedHeight = expandedHeight;
@@ -94,6 +97,8 @@
         mHeight = height;
         mKeyguardStatusHeight = keyguardStatusHeight;
         mEmptyDragAmount = emptyDragAmount;
+        mClockBottom = clockBottom;
+        mDark = dark;
     }
 
     public float getMinStackScrollerPadding(int height, int keyguardStatusHeight) {
@@ -115,6 +120,9 @@
                 result.clockY,
                 y + getClockNotificationsPadding() + mKeyguardStatusHeight);
         result.clockAlpha = getClockAlpha(result.clockScale);
+        if (mDark) {
+            result.stackScrollerPadding = mClockBottom + y;
+        }
     }
 
     private float getClockScale(int notificationPadding, int clockY, int startPadding) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index e4c778c..ff58e54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -28,13 +28,15 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
-import com.android.systemui.BatteryMeterView;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 import java.text.NumberFormat;
@@ -43,7 +45,7 @@
  * The header group on Keyguard.
  */
 public class KeyguardStatusBarView extends RelativeLayout
-        implements BatteryController.BatteryStateChangeCallback {
+        implements BatteryStateChangeCallback, OnUserInfoChangedListener {
 
     private boolean mBatteryCharging;
     private boolean mKeyguardUserSwitcherShowing;
@@ -78,6 +80,7 @@
         mCarrierLabel = (TextView) findViewById(R.id.keyguard_carrier_text);
         loadDimens();
         updateUserSwitcher();
+        mBatteryController = Dependency.get(BatteryController.class);
     }
 
     @Override
@@ -203,23 +206,25 @@
         mMultiUserSwitch.setKeyguardMode(keyguardSwitcherAvailable);
     }
 
-    public void setBatteryController(BatteryController batteryController) {
-        mBatteryController = batteryController;
-        ((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        UserInfoController userInfoController = Dependency.get(UserInfoController.class);
+        userInfoController.addCallback(this);
+        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
+        mMultiUserSwitch.setUserSwitcherController(mUserSwitcherController);
+        userInfoController.reloadUserInfo();
     }
 
-    public void setUserSwitcherController(UserSwitcherController controller) {
-        mUserSwitcherController = controller;
-        mMultiUserSwitch.setUserSwitcherController(controller);
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        Dependency.get(UserInfoController.class).removeCallback(this);
     }
 
-    public void setUserInfoController(UserInfoController userInfoController) {
-        userInfoController.addCallback(new UserInfoController.OnUserInfoChangedListener() {
-            @Override
-            public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
-                mMultiUserAvatar.setImageDrawable(picture);
-            }
-        });
+    @Override
+    public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
+        mMultiUserAvatar.setImageDrawable(picture);
     }
 
     public void setQSPanel(QSPanel qsp) {
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 6dddf18..4535992 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.view.View;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.policy.BatteryController;
 
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -43,17 +44,27 @@
     private boolean mDockedLight;
     private int mLastStatusBarMode;
     private int mLastNavigationBarMode;
+
+    /**
+     * Whether the navigation bar should be light factoring in already how much alpha the scrim has
+     */
     private boolean mNavigationLight;
+
+    /**
+     * Whether the flags indicate that a light status bar is requested. This doesn't factor in the
+     * scrim alpha yet.
+     */
+    private boolean mHasLightNavigationBar;
+    private boolean mScrimAlphaBelowThreshold;
     private float mScrimAlpha;
 
     private final Rect mLastFullscreenBounds = new Rect();
     private final Rect mLastDockedBounds = new Rect();
 
-    public LightBarController(StatusBarIconController statusBarIconController,
-            BatteryController batteryController) {
+    public LightBarController(StatusBarIconController statusBarIconController) {
         mStatusBarIconController = statusBarIconController;
-        mBatteryController = batteryController;
-        batteryController.addCallback(this);
+        mBatteryController = Dependency.get(BatteryController.class);
+        mBatteryController.addCallback(this);
     }
 
     public void setNavigationBar(LightBarTransitionsController navigationBar) {
@@ -101,7 +112,9 @@
         if ((diffVis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
                 || nbModeChanged) {
             boolean last = mNavigationLight;
-            mNavigationLight = isNavigationLight(newVis, navigationBarMode);
+            mHasLightNavigationBar = isLight(vis, navigationBarMode,
+                    View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+            mNavigationLight = mHasLightNavigationBar && mScrimAlphaBelowThreshold;
             if (mNavigationLight != last) {
                 updateNavigation();
             }
@@ -120,12 +133,11 @@
 
     public void setScrimAlpha(float alpha) {
         mScrimAlpha = alpha;
-        reevaluate();
-    }
-
-    private boolean isNavigationLight(int vis, int barMode) {
-        return isLight(vis, barMode, View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR)
-                && mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
+        boolean belowThresholdBefore = mScrimAlphaBelowThreshold;
+        mScrimAlphaBelowThreshold = mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
+        if (mHasLightNavigationBar && belowThresholdBefore != mScrimAlphaBelowThreshold) {
+            reevaluate();
+        }
     }
 
     private boolean isLight(int vis, int barMode, int flag) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
index fc33ace..316bd5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
@@ -38,8 +38,8 @@
     private boolean mListening;
     private int mCurrentUser;
 
-    public ManagedProfileControllerImpl(QSTileHost host) {
-        mContext = host.getContext();
+    public ManagedProfileControllerImpl(Context context) {
+        mContext = context;
         mUserManager = UserManager.get(mContext);
         mProfiles = new LinkedList<UserInfo>();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 4d4f9d2..3cbac17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -29,7 +29,9 @@
 import android.widget.Button;
 import android.widget.FrameLayout;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
@@ -65,7 +67,7 @@
 
     public void setQsPanel(QSPanel qsPanel) {
         mQsPanel = qsPanel;
-        setUserSwitcherController(qsPanel.getHost().getUserSwitcherController());
+        setUserSwitcherController(Dependency.get(UserSwitcherController.class));
     }
 
     public boolean hasMultipleUsers() {
@@ -134,7 +136,7 @@
                 Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
                         getContext(), v, ContactsContract.Profile.CONTENT_URI,
                         ContactsContract.QuickContact.MODE_LARGE, null);
-                mQsPanel.getHost().startActivityDismissingKeyguard(intent);
+                Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(intent, 0);
             }
         }
     }
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 c0f245c..3c46d26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -45,6 +45,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.support.annotation.VisibleForTesting;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -63,7 +64,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.LatencyTracker;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.fragments.FragmentHostManager;
@@ -123,16 +126,17 @@
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mCommandQueue = SystemUIApplication.getComponent(getContext(), CommandQueue.class);
+        mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
         mCommandQueue.addCallbacks(this);
-        mPhoneStatusBar = SystemUIApplication.getComponent(getContext(), PhoneStatusBar.class);
-        mRecents = SystemUIApplication.getComponent(getContext(), Recents.class);
-        mDivider = SystemUIApplication.getComponent(getContext(), Divider.class);
+        mPhoneStatusBar = SysUiServiceProvider.getComponent(getContext(), PhoneStatusBar.class);
+        mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
+        mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
         mWindowManager = getContext().getSystemService(WindowManager.class);
         mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
         if (savedInstanceState != null) {
             mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
         }
+        mAssistManager = Dependency.get(AssistManager.class);
 
         try {
             WindowManagerGlobal.getWindowManagerService()
@@ -399,10 +403,6 @@
         ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
         homeButton.setOnTouchListener(this::onHomeTouch);
         homeButton.setOnLongClickListener(this::onHomeLongClick);
-
-        if (mAssistManager != null) {
-            mAssistManager.onConfigurationChanged();
-        }
     }
 
     private boolean onHomeTouch(View v, MotionEvent event) {
@@ -435,10 +435,6 @@
     }
 
     private void onVerticalChanged(boolean isVertical) {
-        if (mAssistManager != null) {
-            // TODO: Clean this up.
-            mAssistManager.onConfigurationChanged();
-        }
         mPhoneStatusBar.setQsScrimEnabled(!isVertical);
     }
 
@@ -447,7 +443,8 @@
         return false;
     }
 
-    private boolean onHomeLongClick(View v) {
+    @VisibleForTesting
+    boolean onHomeLongClick(View v) {
         if (shouldDisableNavbarGestures()) {
             return false;
         }
@@ -560,10 +557,6 @@
 
     // ----- Methods that PhoneStatusBar talks to (should be minimized) -----
 
-    public void setAssistManager(AssistManager assistManager) {
-        mAssistManager = assistManager;
-    }
-
     public void setLightBarController(LightBarController lightBarController) {
         mLightBarController = lightBarController;
         mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index b6feb0e..f04a9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -365,7 +365,7 @@
     }
 
     @Override
-    public void onPluginConnected(NavBarButtonProvider plugin) {
+    public void onPluginConnected(NavBarButtonProvider plugin, Context context) {
         mPlugins.add(plugin);
         clearViews();
         inflateLayout(mCurrentLayout);
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 31c78c8..319f124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -765,7 +765,7 @@
     }
 
     @Override
-    public void onPluginConnected(NavGesture plugin) {
+    public void onPluginConnected(NavGesture plugin, Context context) {
         mGestureHelper = plugin.getGestureHelper();
         updateTaskSwitchHelper();
     }
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 9fb5980..c25a45c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -22,9 +22,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.util.AttributeSet;
-import android.util.Property;
 import android.view.View;
-import android.view.animation.Interpolator;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -32,7 +30,6 @@
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.stack.AnimationFilter;
 import com.android.systemui.statusbar.stack.AnimationProperties;
-import com.android.systemui.statusbar.stack.HeadsUpAppearInterpolator;
 import com.android.systemui.statusbar.stack.ViewState;
 
 import java.util.HashMap;
@@ -98,6 +95,7 @@
     private int mActualLayoutWidth = NO_VALUE;
     private float mActualPaddingEnd = NO_VALUE;
     private float mActualPaddingStart = NO_VALUE;
+    private boolean mCentered;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
     private int mCannedAnimationStartIndex = -1;
@@ -105,6 +103,7 @@
     private int mIconSize;
     private float mOpenedAmount = 0.0f;
     private float mVisualOverflowAdaption;
+    private boolean mDisallowNextAnimation;
 
     public NotificationIconContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -165,6 +164,7 @@
         }
         mAddAnimationStartIndex = -1;
         mCannedAnimationStartIndex = -1;
+        mDisallowNextAnimation = false;
     }
 
     @Override
@@ -310,6 +310,15 @@
                 numDots++;
             }
         }
+        if (mCentered && translationX < getLayoutEnd()) {
+            float delta = (getLayoutEnd() - translationX) / 2;
+            for (int i = 0; i < childCount; i++) {
+                View view = getChildAt(i);
+                IconState iconState = mIconStates.get(view);
+                iconState.xTranslation += delta;
+            }
+        }
+
         if (isLayoutRtl()) {
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
@@ -379,6 +388,11 @@
         mChangingViewPositions = changingViewPositions;
     }
 
+    public void setAmbient(boolean ambient) {
+        mCentered = ambient;
+        mDisallowNextAnimation = true;
+    }
+
     public IconState getIconState(StatusBarIconView icon) {
         return mIconStates.get(icon);
     }
@@ -469,7 +483,7 @@
                     animate = true;
                 }
                 icon.setVisibleState(visibleState);
-                if (animate) {
+                if (animate && !mDisallowNextAnimation) {
                     animateTo(icon, animationProperties);
                 } else {
                     super.applyToView(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index d48819a..3bdd5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -211,6 +211,7 @@
     private boolean mOpening;
     private int mIndicationBottomPadding;
     private boolean mIsFullWidth;
+    private boolean mDark;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -391,7 +392,9 @@
                     mNotificationStackScroller.getNotGoneChildCount(),
                     getHeight(),
                     mKeyguardStatusView.getHeight(),
-                    mEmptyDragAmount);
+                    mEmptyDragAmount,
+                    mKeyguardStatusView.getClockBottom(),
+                    mDark);
             mClockPositionAlgorithm.run(mClockPositionResult);
             if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockY);
@@ -2453,4 +2456,10 @@
             }
         }
     };
+
+    public void setDark(boolean dark) {
+        mDark = dark;
+        mKeyguardStatusView.setDark(dark);
+        positionClockAndNotifications();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5998ed2..3291d59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -20,6 +20,7 @@
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
+
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
@@ -71,13 +72,11 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -120,15 +119,18 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.BatteryMeterView;
+import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.DemoMode;
+import com.android.systemui.Dependency;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.SystemUIFactory;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeHost;
@@ -137,7 +139,7 @@
 import com.android.systemui.fragments.PluginFragmentListener;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanel;
@@ -167,27 +169,22 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
-import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 import com.android.systemui.statusbar.policy.BatteryControllerImpl;
-import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
-import com.android.systemui.statusbar.policy.CastControllerImpl;
+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.FlashlightControllerImpl;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.HotspotControllerImpl;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
-import com.android.systemui.statusbar.policy.LocationControllerImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl;
-import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.PreviewInflater;
-import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
-import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -304,25 +301,8 @@
 
     PhoneStatusBarPolicy mIconPolicy;
 
-    // These are no longer handled by the policy, because we need custom strategies for them
-    protected BluetoothControllerImpl mBluetoothController;
-    SecurityControllerImpl mSecurityController;
-    protected BatteryController mBatteryController;
-    LocationControllerImpl mLocationController;
-    NetworkControllerImpl mNetworkController;
-    HotspotControllerImpl mHotspotController;
-    RotationLockControllerImpl mRotationLockController;
-    UserInfoControllerImpl mUserInfoController;
-    protected ZenModeController mZenModeController;
-    CastControllerImpl mCastController;
     VolumeComponent mVolumeComponent;
-    KeyguardUserSwitcher mKeyguardUserSwitcher;
-    FlashlightControllerImpl mFlashlightController;
-    protected UserSwitcherController mUserSwitcherController;
-    NextAlarmControllerImpl mNextAlarmController;
-    protected KeyguardMonitorImpl mKeyguardMonitor;
     BrightnessMirrorController mBrightnessMirrorController;
-    AccessibilityController mAccessibilityController;
     protected FingerprintUnlockController mFingerprintUnlockController;
     LightBarController mLightBarController;
     protected LockscreenWallpaper mLockscreenWallpaper;
@@ -409,23 +389,16 @@
         : null;
 
     private ScreenPinningRequest mScreenPinningRequest;
-    private HandlerThread mHandlerThread;
-    private HandlerThread mTimeTickThread;
-    private Handler mTimeTickHandler;
 
     // ensure quick settings is disabled until the current user makes it through the setup wizard
     private boolean mUserSetup = false;
-    private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
+    private DeviceProvisionedListener mUserSetupObserver = new DeviceProvisionedListener() {
         @Override
-        public void onChange(boolean selfChange) {
-            final boolean userSetup = 0 != Settings.Secure.getIntForUser(
-                    mContext.getContentResolver(),
-                    Settings.Secure.USER_SETUP_COMPLETE,
-                    0 /*default */,
-                    mCurrentUserId);
+        public void onUserSetupChanged() {
+            final boolean userSetup = mDeviceProvisionedController.isUserSetup(
+                    mDeviceProvisionedController.getCurrentUser());
             if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
-                    "selfChange=%s userSetup=%s mUserSetup=%s",
-                    selfChange, userSetup, mUserSetup));
+                    "userSetup=%s mUserSetup=%s", userSetup, mUserSetup));
 
             if (userSetup != mUserSetup) {
                 mUserSetup = userSetup;
@@ -434,9 +407,7 @@
                 if (mKeyguardBottomArea != null) {
                     mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
                 }
-                if (mNetworkController != null) {
-                    mNetworkController.setUserSetupComplete(mUserSetup);
-                }
+                updateQsExpansionEnabled();
             }
             if (mIconPolicy != null) {
                 mIconPolicy.setCurrentUserSetup(mUserSetup);
@@ -637,6 +608,13 @@
         }
     };
 
+    private KeyguardUserSwitcher mKeyguardUserSwitcher;
+    private UserSwitcherController mUserSwitcherController;
+    private NetworkController mNetworkController;
+    private KeyguardMonitorImpl mKeyguardMonitor;
+    private BatteryController mBatteryController;
+    private DeviceProvisionedController mDeviceProvisionedController;
+
     private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
         final int N = array.size();
         for (int i = 0 ; i < N; i++) {
@@ -670,19 +648,20 @@
 
     @Override
     public void start() {
+        mNetworkController = Dependency.get(NetworkController.class);
+        mUserSwitcherController = Dependency.get(UserSwitcherController.class);
+        mKeyguardMonitor = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
+        mBatteryController = Dependency.get(BatteryController.class);
+        mAssistManager = Dependency.get(AssistManager.class);
+        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
+
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
         updateDisplaySize();
         mScrimSrcModeEnabled = mContext.getResources().getBoolean(
                 R.bool.config_status_bar_scrim_behind_use_src);
 
-        // Background thread for any controllers that need it.
-        mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
-        mHandlerThread.start();
-        mTimeTickThread = new HandlerThread("TimeTick");
-        mTimeTickThread.start();
-        mTimeTickHandler = new Handler(mTimeTickThread.getLooper());
-        DateTimeView.setReceiverHandler(mTimeTickHandler);
+        DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
         putComponent(PhoneStatusBar.class, this);
 
         super.start(); // calls createAndAddWindows()
@@ -693,9 +672,7 @@
         // in session state
 
         // Lastly, call to the icon policy to install/update all the icons.
-        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
-                mHotspotController, mUserInfoController, mBluetoothController,
-                mRotationLockController, mNetworkController.getDataSaverController(), mNextAlarmController);
+        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
         mIconPolicy.setCurrentUserSetup(mUserSetup);
         mSettingsObserver.onChange(false); // set up
 
@@ -716,12 +693,11 @@
         mDozeServiceHost = new DozeServiceHost();
         putComponent(DozeHost.class, mDozeServiceHost);
 
-        setControllerUsers();
-
         notifyUserAboutHiddenNotifications();
 
         mScreenPinningRequest = new ScreenPinningRequest(mContext);
         mFalsingManager = FalsingManager.getInstance(mContext);
+        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
     }
 
     protected void createIconController() {
@@ -795,8 +771,6 @@
             // no window manager? good luck with that
         }
 
-        mAssistManager = SystemUIFactory.getInstance().createAssistManager(this, context);
-
         // figure out which pixel-format to use for the status bar.
         mPixelFormat = PixelFormat.OPAQUE;
 
@@ -827,8 +801,6 @@
                 (KeyguardStatusView) mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
                 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
-        mKeyguardBottomArea.setActivityStarter(this);
-        mKeyguardBottomArea.setAssistManager(mAssistManager);
         mKeyguardIndicationController = new KeyguardIndicationController(mContext,
                 (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
                 mKeyguardBottomArea.getLockIcon());
@@ -839,7 +811,7 @@
 
         createIconController();
 
-        mBatteryController = createBatteryController();
+        // TODO: Find better place for this callback.
         mBatteryController.addCallback(new BatteryStateChangeCallback() {
             @Override
             public void onPowerSaveChanged(boolean isPowerSave) {
@@ -848,13 +820,14 @@
                     mDozeServiceHost.firePowerSaveChanged(isPowerSave);
                 }
             }
+
             @Override
             public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
                 // noop
             }
         });
 
-        mLightBarController = new LightBarController(mIconController, mBatteryController);
+        mLightBarController = new LightBarController(mIconController);
         if (mNavigationBar != null) {
             mNavigationBar.setLightBarController(mLightBarController);
         }
@@ -879,39 +852,16 @@
         mHeadsUpManager.addListener(mScrimController);
         mStackScroller.setScrimController(mScrimController);
         mStatusBarView.setScrimController(mScrimController);
-        mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller);
+        mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller,
+                mNotificationPanel);
 
         // Other icons
-        mLocationController = new LocationControllerImpl(mContext,
-                mHandlerThread.getLooper()); // will post a notification
-        mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
-        mNetworkController.setUserSetupComplete(mUserSetup);
-        mHotspotController = new HotspotControllerImpl(mContext);
-        mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
-        mSecurityController = new SecurityControllerImpl(mContext);
-        if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) {
-            mRotationLockController = new RotationLockControllerImpl(mContext);
-        }
-        mUserInfoController = new UserInfoControllerImpl(mContext);
         mVolumeComponent = getComponent(VolumeComponent.class);
-        if (mVolumeComponent != null) {
-            mZenModeController = mVolumeComponent.getZenController();
-        }
-        mCastController = new CastControllerImpl(mContext);
 
-        initSignalCluster(mStatusBarView);
-        initSignalCluster(mKeyguardStatusBar);
         initEmergencyCryptkeeperText();
 
-        mFlashlightController = new FlashlightControllerImpl(mContext);
-        mKeyguardBottomArea.setFlashlightController(mFlashlightController);
         mKeyguardBottomArea.setPhoneStatusBar(this);
         mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
-        mAccessibilityController = new AccessibilityController(mContext);
-        mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
-        mNextAlarmController = new NextAlarmControllerImpl(mContext);
-        mKeyguardMonitor = new KeyguardMonitorImpl(mContext);
-            mUserSwitcherController = createUserSwitcherController();
         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
             createUserSwitcher();
         }
@@ -920,15 +870,13 @@
         View container = mStatusBarWindow.findViewById(R.id.qs_frame);
         if (container != null) {
             FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
-            new PluginFragmentListener(container, QS.TAG, R.id.qs_frame, QSFragment.class, QS.class)
+            fragmentHostManager.getFragmentManager().beginTransaction()
+                    .replace(R.id.qs_frame, new QSFragment(), QS.TAG)
+                    .commit();
+            new PluginFragmentListener(container, QS.TAG, QSFragment.class, QS.class)
                     .startListening(QS.ACTION, QS.VERSION);
             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
-                    mBluetoothController, mLocationController, mRotationLockController,
-                    mNetworkController, mZenModeController, mHotspotController,
-                    mCastController, mFlashlightController,
-                    mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
-                    mSecurityController, mBatteryController, mIconController,
-                    mNextAlarmController);
+                    mIconController);
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
             fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
                 QS qs = (QS) f;
@@ -938,21 +886,9 @@
                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
                     mKeyguardStatusBar.setQSPanel(mQSPanel);
                 }
-                mHeader = qs.getHeader();
-                initSignalCluster(mHeader);
-                mHeader.setActivityStarter(PhoneStatusBar.this);
             });
         }
 
-        // User info. Trigger first load.
-        mKeyguardStatusBar.setUserInfoController(mUserInfoController);
-        mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
-        mUserInfoController.reloadUserInfo();
-
-        ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
-                mBatteryController);
-        mKeyguardStatusBar.setBatteryController(mBatteryController);
-
         mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
         if (mReportRejectedTouch != null) {
             updateReportRejectedTouchVisibility();
@@ -1013,7 +949,8 @@
                 android.Manifest.permission.DUMP, null);
 
         // listen for USER_SETUP_COMPLETE setting (per-user)
-        resetUserSetupObserver();
+        mDeviceProvisionedController.addCallback(mUserSetupObserver);
+        mUserSetupObserver.onUserSetupChanged();
 
         // disable profiling bars, since they overlap and clutter the output on app windows
         ThreadedRenderer.overrideProperty("disableProfileBars", "true");
@@ -1024,19 +961,9 @@
         return mStatusBarView;
     }
 
-    public Handler getTimeTickHandler() {
-        return mTimeTickHandler;
-    }
-
-    public static Handler getTimeTickHandler(Context context) {
-        return ((SystemUIApplication) context.getApplicationContext())
-                .getComponent(PhoneStatusBar.class).getTimeTickHandler();
-    }
-
     protected void createNavigationBar() {
         mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
             mNavigationBar = (NavigationBarFragment) fragment;
-            mNavigationBar.setAssistManager(mAssistManager);
             if (mLightBarController != null) {
                 mNavigationBar.setLightBarController(mLightBarController);
             }
@@ -1062,10 +989,6 @@
         }
     }
 
-    protected BatteryController createBatteryController() {
-        return new BatteryControllerImpl(mContext);
-    }
-
     private void inflateShelf() {
         mNotificationShelf =
                 (NotificationShelf) LayoutInflater.from(mContext).inflate(
@@ -1091,10 +1014,10 @@
         inflateEmptyShadeView();
         updateEmptyShadeView();
         mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
-        mUserInfoController.onDensityOrFontScaleChanged();
-        if (mUserSwitcherController != null) {
-            mUserSwitcherController.onDensityOrFontScaleChanged();
-        }
+        // TODO: Bring these out of PhoneStatusBar.
+        ((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
+                .onDensityOrFontScaleChanged();
+        Dependency.get(UserSwitcherController.class).onDensityOrFontScaleChanged();
         if (mKeyguardUserSwitcher != null) {
             mKeyguardUserSwitcher.onDensityOrFontScaleChanged();
         }
@@ -1124,8 +1047,6 @@
                                 R.dimen.signal_cluster_margin_start),
                         0, 0, 0);
                 newCluster.setLayoutParams(layoutParams);
-                newCluster.setSecurityController(mSecurityController);
-                newCluster.setNetworkController(mNetworkController);
                 viewParent.addView(newCluster, index);
                 return newCluster;
             }
@@ -1156,11 +1077,7 @@
     protected void createUserSwitcher() {
         mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext,
                 (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher),
-                mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController);
-    }
-
-    protected UserSwitcherController createUserSwitcherController() {
-        return new UserSwitcherController(mContext, mKeyguardMonitor, mHandler, this);
+                mKeyguardStatusBar, mNotificationPanel);
     }
 
     protected void inflateStatusBarWindow(Context context) {
@@ -1168,15 +1085,6 @@
                 R.layout.super_status_bar, null);
     }
 
-    protected void initSignalCluster(View containerView) {
-        SignalClusterView signalCluster =
-                (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
-        if (signalCluster != null) {
-            signalCluster.setSecurityController(mSecurityController);
-            signalCluster.setNetworkController(mNetworkController);
-        }
-    }
-
     public void clearAllNotifications() {
 
         // animate-swipe all dismissable notifications, then animate the shade closed
@@ -2378,6 +2286,11 @@
     }
 
     @Override
+    public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade) {
+        startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade);
+    }
+
+    @Override
     public void startActivity(Intent intent, boolean dismissShade, Callback callback) {
         startActivityDismissingKeyguard(intent, false, dismissShade, callback);
     }
@@ -2401,6 +2314,7 @@
         return getBarState() == StatusBarState.KEYGUARD;
     }
 
+    @Override
     public boolean isDozing() {
         return mDozing;
     }
@@ -2487,6 +2401,9 @@
             }
         } else {
             updateNotificationRanking(null);
+            if (isHeadsUp) {
+                mDozeServiceHost.fireNotificationHeadsUp();
+            }
         }
 
     }
@@ -2886,9 +2803,6 @@
 
     @Override // CommandQueue
     public void buzzBeepBlinked() {
-        if (mDozeServiceHost != null) {
-            mDozeServiceHost.fireBuzzBeepBlinked();
-        }
     }
 
     @Override
@@ -3223,30 +3137,7 @@
         if (mStatusBarWindowManager != null) {
             mStatusBarWindowManager.dump(fd, pw, args);
         }
-        if (mNetworkController != null) {
-            mNetworkController.dump(fd, pw, args);
-        }
-        if (mBluetoothController != null) {
-            mBluetoothController.dump(fd, pw, args);
-        }
-        if (mHotspotController != null) {
-            mHotspotController.dump(fd, pw, args);
-        }
-        if (mCastController != null) {
-            mCastController.dump(fd, pw, args);
-        }
-        if (mUserSwitcherController != null) {
-            mUserSwitcherController.dump(fd, pw, args);
-        }
-        if (mBatteryController != null) {
-            mBatteryController.dump(fd, pw, args);
-        }
-        if (mNextAlarmController != null) {
-            mNextAlarmController.dump(fd, pw, args);
-        }
-        if (mSecurityController != null) {
-            mSecurityController.dump(fd, pw, args);
-        }
+
         if (mHeadsUpManager != null) {
             mHeadsUpManager.dump(fd, pw, args);
         } else {
@@ -3260,9 +3151,6 @@
         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
         }
-        if (mFlashlightController != null) {
-            mFlashlightController.dump(fd, pw, args);
-        }
 
         FalsingManager.getInstance(mContext).dump(pw);
         FalsingLog.dump(pw);
@@ -3489,7 +3377,6 @@
 
         updateRowStates();
         mScreenPinningRequest.onConfigurationChanged();
-        mNetworkController.onConfigurationChanged();
     }
 
     @Override
@@ -3499,8 +3386,6 @@
         animateCollapsePanels();
         updatePublicMode();
         updateNotifications();
-        resetUserSetupObserver();
-        setControllerUsers();
         clearCurrentMediaNotification();
         setLockscreenUser(newUserId);
     }
@@ -3511,23 +3396,6 @@
         updateMediaMetaData(true, false);
     }
 
-    private void setControllerUsers() {
-        if (mZenModeController != null) {
-            mZenModeController.setUserId(mCurrentUserId);
-        }
-        if (mSecurityController != null) {
-            mSecurityController.onUserSwitched(mCurrentUserId);
-        }
-    }
-
-    private void resetUserSetupObserver() {
-        mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
-        mUserSetupObserver.onChange(false);
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
-                mUserSetupObserver, mCurrentUserId);
-    }
-
     /**
      * Reload some of our resources when the configuration changes.
      *
@@ -3708,32 +3576,23 @@
         }
     };
 
+    @Override
     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mLeaveOpenOnKeyguardHide = true;
-                executeRunnableDismissingKeyguard(runnable, null, false, false, false);
-            }
+        mHandler.post(() -> {
+            mLeaveOpenOnKeyguardHide = true;
+            executeRunnableDismissingKeyguard(runnable, null, false, false, false);
         });
     }
 
+    @Override
     public void postStartActivityDismissingKeyguard(final PendingIntent intent) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                startPendingIntentDismissingKeyguard(intent);
-            }
-        });
+        mHandler.post(() -> startPendingIntentDismissingKeyguard(intent));
     }
 
+    @Override
     public void postStartActivityDismissingKeyguard(final Intent intent, int delay) {
-        mHandler.postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/);
-            }
-        }, delay);
+        mHandler.postDelayed(() ->
+                handleStartActivityDismissingKeyguard(intent, true /*onlyProvisioned*/), delay);
     }
 
     private void handleStartActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
@@ -3785,10 +3644,6 @@
             mWindowManager.removeViewImmediate(mNavigationBarView);
             mNavigationBarView = null;
         }
-        if (mHandlerThread != null) {
-            mHandlerThread.quitSafely();
-            mHandlerThread = null;
-        }
         mContext.unregisterReceiver(mBroadcastReceiver);
         mContext.unregisterReceiver(mDemoReceiver);
         mAssistManager.destroy();
@@ -3799,12 +3654,11 @@
                 (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
         final SignalClusterView signalClusterQs =
                 (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
-        mNetworkController.removeCallback(signalCluster);
-        mNetworkController.removeCallback(signalClusterKeyguard);
-        mNetworkController.removeCallback(signalClusterQs);
         if (mQSPanel != null && mQSPanel.getHost() != null) {
             mQSPanel.getHost().destroy();
         }
+        Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
+        mDeviceProvisionedController.removeCallback(mUserSetupObserver);
     }
 
     private boolean mDemoModeAllowed;
@@ -4234,6 +4088,7 @@
         mDozeScrimController.setDozing(mDozing &&
                 mFingerprintUnlockController.getMode()
                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
+        updateRowStates();
         Trace.endSection();
     }
 
@@ -4904,9 +4759,9 @@
             }
         }
 
-        public void fireBuzzBeepBlinked() {
+        public void fireNotificationHeadsUp() {
             for (Callback callback : mCallbacks) {
-                callback.onBuzzBeepBlinked();
+                callback.onNotificationHeadsUp();
             }
         }
 
@@ -4950,12 +4805,14 @@
                 public void onPulseStarted() {
                     callback.onPulseStarted();
                     mStackScroller.setPulsing(true);
+                    mVisualStabilityManager.setPulsing(true);
                 }
 
                 @Override
                 public void onPulseFinished() {
                     callback.onPulseFinished();
                     mStackScroller.setPulsing(false);
+                    mVisualStabilityManager.setPulsing(false);
                 }
             }, reason);
         }
@@ -4976,7 +4833,7 @@
 
         @Override
         public boolean isPowerSaveActive() {
-            return mBatteryController != null && mBatteryController.isPowerSave();
+            return mBatteryController.isPowerSave();
         }
 
         @Override
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 9ee1e8f..1044ecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
@@ -99,22 +100,19 @@
 
     private BluetoothController mBluetooth;
 
-    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController,
-            CastController cast, HotspotController hotspot, UserInfoController userInfoController,
-            BluetoothController bluetooth, RotationLockController rotationLockController,
-            DataSaverController dataSaver, NextAlarmController nextAlarm) {
+    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {
         mContext = context;
         mIconController = iconController;
-        mCast = cast;
-        mHotspot = hotspot;
-        mBluetooth = bluetooth;
+        mCast = Dependency.get(CastController.class);
+        mHotspot = Dependency.get(HotspotController.class);
+        mBluetooth = Dependency.get(BluetoothController.class);
         mBluetooth.addCallback(this);
-        mNextAlarm = nextAlarm;
+        mNextAlarm = Dependency.get(NextAlarmController.class);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        mUserInfoController = userInfoController;
+        mUserInfoController = Dependency.get(UserInfoController.class);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mRotationLockController = rotationLockController;
-        mDataSaver = dataSaver;
+        mRotationLockController = Dependency.get(RotationLockController.class);
+        mDataSaver = Dependency.get(DataSaverController.class);
 
         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
         mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 227ebdf..2f76cb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -17,15 +17,11 @@
 package com.android.systemui.statusbar.phone;
 
 import android.app.ActivityManager;
-import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -33,8 +29,8 @@
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.View;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.external.CustomTile;
@@ -52,25 +48,12 @@
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.IntentTile;
 import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.NfcTile;
 import com.android.systemui.qs.tiles.NightDisplayTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.UserTile;
 import com.android.systemui.qs.tiles.WifiTile;
 import com.android.systemui.qs.tiles.WorkModeTile;
-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.NextAlarmController;
-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.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.tuner.TunerService.Tunable;
 
@@ -79,7 +62,6 @@
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 
 /** Platform implementation of the quick settings tile host **/
 public class QSTileHost implements QSTile.Host, Tunable {
@@ -92,81 +74,31 @@
     private final PhoneStatusBar mStatusBar;
     private final LinkedHashMap<String, QSTile<?>> mTiles = new LinkedHashMap<>();
     protected final ArrayList<String> mTileSpecs = new ArrayList<>();
-    private final BluetoothController mBluetooth;
-    private final LocationController mLocation;
-    private final RotationLockController mRotation;
-    private final NetworkController mNetwork;
-    private final ZenModeController mZen;
-    private final HotspotController mHotspot;
-    private final CastController mCast;
-    private final Looper mLooper;
-    private final FlashlightController mFlashlight;
-    private final UserSwitcherController mUserSwitcherController;
-    private final UserInfoController mUserInfoController;
-    private final KeyguardMonitor mKeyguard;
-    private final SecurityController mSecurity;
-    private final BatteryController mBattery;
-    private final StatusBarIconController mIconController;
     private final TileServices mServices;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
     private final AutoTileManager mAutoTiles;
-    private final ManagedProfileController mProfileController;
-    private final NextAlarmController mNextAlarmController;
-    private final HandlerThread mHandlerThread;
-    private View mHeader;
+    private final StatusBarIconController mIconController;
     private int mCurrentUser;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
-            BluetoothController bluetooth, LocationController location,
-            RotationLockController rotation, NetworkController network,
-            ZenModeController zen, HotspotController hotspot,
-            CastController cast, FlashlightController flashlight,
-            UserSwitcherController userSwitcher, UserInfoController userInfo,
-            KeyguardMonitor keyguard, SecurityController security,
-            BatteryController battery, StatusBarIconController iconController,
-            NextAlarmController nextAlarmController) {
+            StatusBarIconController iconController) {
+        mIconController = iconController;
         mContext = context;
         mStatusBar = statusBar;
-        mBluetooth = bluetooth;
-        mLocation = location;
-        mRotation = rotation;
-        mNetwork = network;
-        mZen = zen;
-        mHotspot = hotspot;
-        mCast = cast;
-        mFlashlight = flashlight;
-        mUserSwitcherController = userSwitcher;
-        mUserInfoController = userInfo;
-        mKeyguard = keyguard;
-        mSecurity = security;
-        mBattery = battery;
-        mIconController = iconController;
-        mNextAlarmController = nextAlarmController;
-        mProfileController = new ManagedProfileControllerImpl(this);
 
-        mHandlerThread = new HandlerThread(QSTileHost.class.getSimpleName(),
-                Process.THREAD_PRIORITY_BACKGROUND);
-        mHandlerThread.start();
-        mLooper = mHandlerThread.getLooper();
-
-        mServices = new TileServices(this, mLooper);
+        mServices = new TileServices(this, Dependency.get(Dependency.BG_LOOPER));
 
         TunerService.get(mContext).addTunable(this, TILES_SETTING);
         // AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
         mAutoTiles = new AutoTileManager(context, this);
     }
 
-    public NextAlarmController getNextAlarmController() {
-        return mNextAlarmController;
-    }
-
-    public void setHeaderView(View view) {
-        mHeader = view;
+    public StatusBarIconController getIconController() {
+        return mIconController;
     }
 
     public void destroy() {
-        mHandlerThread.quitSafely();
         mTiles.values().forEach(tile -> tile.destroy());
         mAutoTiles.destroy();
         TunerService.get(mContext).removeTunable(this);
@@ -189,30 +121,10 @@
     }
 
     @Override
-    public void startActivityDismissingKeyguard(final Intent intent) {
-        mStatusBar.postStartActivityDismissingKeyguard(intent, 0);
-    }
-
-    @Override
-    public void startActivityDismissingKeyguard(PendingIntent intent) {
-        mStatusBar.postStartActivityDismissingKeyguard(intent);
-    }
-
-    @Override
-    public void startRunnableDismissingKeyguard(Runnable runnable) {
-        mStatusBar.postQSRunnableDismissingKeyguard(runnable);
-    }
-
-    @Override
     public void warn(String message, Throwable t) {
         // already logged
     }
 
-    public void animateToggleQSExpansion() {
-        // TODO: Better path to animated panel expansion.
-        mHeader.callOnClick();
-    }
-
     @Override
     public void collapsePanels() {
         mStatusBar.postAnimateCollapsePanels();
@@ -224,91 +136,15 @@
     }
 
     @Override
-    public Looper getLooper() {
-        return mLooper;
-    }
-
-    @Override
     public Context getContext() {
         return mContext;
     }
 
-    @Override
-    public BluetoothController getBluetoothController() {
-        return mBluetooth;
-    }
-
-    @Override
-    public LocationController getLocationController() {
-        return mLocation;
-    }
-
-    @Override
-    public RotationLockController getRotationLockController() {
-        return mRotation;
-    }
-
-    @Override
-    public NetworkController getNetworkController() {
-        return mNetwork;
-    }
-
-    @Override
-    public ZenModeController getZenModeController() {
-        return mZen;
-    }
-
-    @Override
-    public HotspotController getHotspotController() {
-        return mHotspot;
-    }
-
-    @Override
-    public CastController getCastController() {
-        return mCast;
-    }
-
-    @Override
-    public FlashlightController getFlashlightController() {
-        return mFlashlight;
-    }
-
-    @Override
-    public KeyguardMonitor getKeyguardMonitor() {
-        return mKeyguard;
-    }
-
-    @Override
-    public UserSwitcherController getUserSwitcherController() {
-        return mUserSwitcherController;
-    }
-
-    @Override
-    public UserInfoController getUserInfoController() {
-        return mUserInfoController;
-    }
-
-    @Override
-    public BatteryController getBatteryController() {
-        return mBattery;
-    }
-
-    public SecurityController getSecurityController() {
-        return mSecurity;
-    }
 
     public TileServices getTileServices() {
         return mServices;
     }
 
-    public StatusBarIconController getIconController() {
-        return mIconController;
-    }
-
-    public ManagedProfileController getManagedProfileController() {
-        return mProfileController;
-    }
-
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!TILES_SETTING.equals(key)) {
@@ -440,6 +276,7 @@
         else if (tileSpec.equals("battery")) return new BatteryTile(this);
         else if (tileSpec.equals("saver")) return new DataSaverTile(this);
         else if (tileSpec.equals("night")) return new NightDisplayTile(this);
+        else if (tileSpec.equals("nfc")) return new NfcTile(this);
         // Intent tiles.
         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
         else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
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 08a91bb..9e93802 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -21,9 +21,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
+import android.icu.text.NumberFormat;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -32,20 +36,24 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.keyguard.KeyguardStatusView;
+import com.android.settingslib.Utils;
+import com.android.systemui.ActivityStarter;
+import com.android.systemui.BatteryMeterView;
+import com.android.systemui.Dependency;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
-import com.android.systemui.plugins.qs.QS.ActivityStarter;
 import com.android.systemui.plugins.qs.QS.BaseStatusBarHeader;
-import com.android.systemui.qs.QSPanel;
 import com.android.systemui.plugins.qs.QS.Callback;
+import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
@@ -54,7 +62,8 @@
 import com.android.systemui.tuner.TunerService;
 
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
-        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener {
+        NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener,
+        BatteryStateChangeCallback {
 
     private static final String TAG = "QuickStatusBarHeader";
 
@@ -62,19 +71,20 @@
 
     private ActivityStarter mActivityStarter;
     private NextAlarmController mNextAlarmController;
+    private UserInfoController mUserInfoController;
     private SettingsButton mSettingsButton;
     protected View mSettingsContainer;
 
     private TextView mAlarmStatus;
     private View mAlarmStatusCollapsed;
+    private ViewGroup mDateTimeGroup;
+    private ViewGroup mDateTimeAlarmGroup;
 
     private QSPanel mQsPanel;
 
     private boolean mExpanded;
     private boolean mAlarmShowing;
 
-    private ViewGroup mDateTimeGroup;
-    private ViewGroup mDateTimeAlarmGroup;
     private TextView mEmergencyOnly;
 
     protected ExpandableIndicator mExpandIndicator;
@@ -95,6 +105,7 @@
     protected View mEdit;
     private boolean mShowFullAlarm;
     private float mDateTimeTranslation;
+    private TextView mBatteryLevel;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -108,7 +119,8 @@
 
         mEdit = findViewById(android.R.id.edit);
         findViewById(android.R.id.edit).setOnClickListener(view ->
-                mHost.startRunnableDismissingKeyguard(() -> mQsPanel.showEdit(view)));
+                Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
+                        mQsPanel.showEdit(view)));
 
         mDateTimeAlarmGroup = (ViewGroup) findViewById(R.id.date_time_alarm_group);
         mDateTimeAlarmGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
@@ -130,6 +142,8 @@
         mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
         mAlarmStatus.setOnClickListener(this);
 
+        mBatteryLevel = (TextView) findViewById(R.id.battery_level);
+
         mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
         mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
 
@@ -139,6 +153,15 @@
         ((RippleDrawable) mExpandIndicator.getBackground()).setForceSoftware(true);
 
         updateResources();
+
+        // Set the light/dark theming on the header status UI to match the current theme.
+        SignalClusterView cluster = (SignalClusterView) findViewById(R.id.signal_cluster);
+        int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
+        float intensity = colorForeground / (float) Color.WHITE;
+        cluster.setIconTint(colorForeground, intensity, new Rect(0, 0, 0, 0));
+        BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery);
+        int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
+        battery.setRawColors(colorForeground, colorSecondary);
     }
 
     @Override
@@ -237,12 +260,17 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mNextAlarmController = Dependency.get(NextAlarmController.class);
+        mUserInfoController = Dependency.get(UserInfoController.class);
+        mActivityStarter = Dependency.get(ActivityStarter.class);
+    }
+
+    @Override
     @VisibleForTesting
     public void onDetachedFromWindow() {
         setListening(false);
-        mHost.getUserInfoController().removeCallback(this);
-        mHost.getNetworkController().removeEmergencyListener(this);
-        mHost.getUserInfoController().removeCallback(this);
         super.onDetachedFromWindow();
     }
 
@@ -294,16 +322,17 @@
     private void updateListeners() {
         if (mListening) {
             mNextAlarmController.addCallback(this);
+            mUserInfoController.addCallback(this);
+            if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
+                Dependency.get(NetworkController.class).addEmergencyListener(this);
+            }
         } else {
             mNextAlarmController.removeCallback(this);
+            mUserInfoController.removeCallback(this);
+            Dependency.get(NetworkController.class).removeEmergencyListener(this);
         }
     }
 
-    @Override
-    public void setActivityStarter(ActivityStarter activityStarter) {
-        mActivityStarter = activityStarter;
-    }
-
     public void setQSPanel(final QSPanel qsPanel) {
         mQsPanel = qsPanel;
         setupHost(qsPanel.getHost());
@@ -314,17 +343,9 @@
 
     public void setupHost(final QSTileHost host) {
         mHost = host;
-        host.setHeaderView(mExpandIndicator);
+        //host.setHeaderView(mExpandIndicator);
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
         mHeaderQsPanel.setHost(host, null /* No customization in header */);
-        setUserInfoController(host.getUserInfoController());
-        setBatteryController(host.getBatteryController());
-        setNextAlarmController(host.getNextAlarmController());
-
-        final boolean isAPhone = mHost.getNetworkController().hasVoiceCallingFeature();
-        if (isAPhone) {
-            mHost.getNetworkController().addEmergencyListener(this);
-        }
     }
 
     @Override
@@ -334,7 +355,7 @@
                     mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
                             : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
             if (mSettingsButton.isTunerClick()) {
-                mHost.startRunnableDismissingKeyguard(() -> post(() -> {
+                Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
                     if (TunerService.isTunerEnabled(mContext)) {
                         TunerService.showResetRequest(mContext, () -> {
                             // Relaunch settings so that the tuner disappears.
@@ -347,7 +368,7 @@
                     }
                     startSettingsActivity();
 
-                }));
+                });
             } else {
                 startSettingsActivity();
             }
@@ -362,18 +383,6 @@
                 true /* dismissShade */);
     }
 
-    public void setNextAlarmController(NextAlarmController nextAlarmController) {
-        mNextAlarmController = nextAlarmController;
-    }
-
-    public void setBatteryController(BatteryController batteryController) {
-        // Don't care
-    }
-
-    public void setUserInfoController(UserInfoController userInfoController) {
-        userInfoController.addCallback(this);
-    }
-
     @Override
     public void setCallback(Callback qsPanelCallback) {
         mHeaderQsPanel.setCallback(qsPanelCallback);
@@ -391,6 +400,17 @@
     }
 
     @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+        mBatteryLevel.setText(percentage);
+    }
+
+    @Override
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        // Don't care.
+    }
+
+    @Override
     public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
         mMultiUserAvatar.setImageDrawable(picture);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 517551d..8fcbf38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -338,13 +338,13 @@
     private void setCurrentScrimAlpha(View scrim, float alpha) {
         if (scrim == mScrimBehind) {
             mCurrentBehindAlpha = alpha;
+            mLightBarController.setScrimAlpha(mCurrentBehindAlpha);
         } else if (scrim == mScrimInFront) {
             mCurrentInFrontAlpha = alpha;
         } else {
             alpha = Math.max(0.0f, Math.min(1.0f, alpha));
             mCurrentHeadsUpAlpha = alpha;
         }
-        mLightBarController.setScrimAlpha(mCurrentBehindAlpha);
     }
 
     protected void updateScrimColor(View scrim) {
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 2e279b2..7e5a7da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -491,7 +491,7 @@
     private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() {
         @Override
         public void run() {
-            mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE);
+            mPhoneStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE);
         }
     };
 
@@ -527,7 +527,7 @@
                     }
                 } else {
                     mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable);
-                    mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
+                    mPhoneStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 19dcf03..48ff1c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -17,12 +17,13 @@
 package com.android.systemui.statusbar.policy;
 
 import com.android.systemui.DemoMode;
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-public interface BatteryController extends DemoMode,
+public interface BatteryController extends DemoMode, Dumpable,
         CallbackController<BatteryStateChangeCallback> {
     /**
      * Prints the current state of the {@link BatteryController} to the given {@link PrintWriter}.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 4c1c378..df30e20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -17,11 +17,12 @@
 package com.android.systemui.statusbar.policy;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.BluetoothController.Callback;
 
 import java.util.Collection;
 
-public interface BluetoothController extends CallbackController<Callback> {
+public interface BluetoothController extends CallbackController<Callback>, Dumpable {
     boolean isBluetoothSupported();
     boolean isBluetoothEnabled();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
index 3142ddf..e7056a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
@@ -47,7 +47,7 @@
     private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>();
 
     public CallbackHandler() {
-        super();
+        super(Looper.getMainLooper());
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index 6988af7..97be6ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -16,11 +16,12 @@
 
 package com.android.systemui.statusbar.policy;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.CastController.Callback;
 
 import java.util.Set;
 
-public interface CastController extends CallbackController<Callback> {
+public interface CastController extends CallbackController<Callback>, Dumpable {
     void setDiscovering(boolean request);
     void setCurrentUserId(int currentUserId);
     Set<CastDevice> getCastDevices();
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 1dbc664..9cc9749 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -38,8 +38,8 @@
 import android.widget.TextView;
 
 import com.android.systemui.DemoMode;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
@@ -107,7 +107,7 @@
             filter.addAction(Intent.ACTION_USER_SWITCHED);
 
             getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter,
-                    null, PhoneStatusBar.getTimeTickHandler(getContext()));
+                    null, Dependency.get(Dependency.TIME_TICK_HANDLER));
             TunerService.get(getContext()).addTunable(this, CLOCK_SECONDS,
                     StatusBarIconController.ICON_BLACKLIST);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 5544c70..dc33633 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -23,12 +23,11 @@
 import android.content.res.TypedArray;
 import android.icu.text.DateFormat;
 import android.icu.text.DisplayContext;
-import android.os.Handler;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.Date;
 import java.util.Locale;
@@ -87,7 +86,7 @@
         filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
         getContext().registerReceiver(mIntentReceiver, filter, null,
-                PhoneStatusBar.getTimeTickHandler(getContext()));
+                Dependency.get(Dependency.TIME_TICK_HANDLER));
 
         updateClock();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
new file mode 100644
index 0000000..aa4eaa7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
@@ -0,0 +1,32 @@
+/*
+ * 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.Context;
+
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+public interface DeviceProvisionedController extends CallbackController<DeviceProvisionedListener> {
+
+    boolean isDeviceProvisioned();
+    boolean isUserSetup(int currentUser);
+    int getCurrentUser();
+
+    interface DeviceProvisionedListener {
+        default void onDeviceProvisionedChanged() { }
+        default void onUserSwitched() { }
+        default void onUserSetupChanged() { }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
new file mode 100644
index 0000000..0fc300d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -0,0 +1,124 @@
+/*
+ * 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.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.settings.CurrentUserTracker;
+
+import java.util.ArrayList;
+
+public class DeviceProvisionedControllerImpl extends CurrentUserTracker implements
+        DeviceProvisionedController {
+
+    private final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>();
+    private final ContentResolver mContentResolver;
+    private final Context mContext;
+    private final Uri mDeviceProvisionedUri;
+    private final Uri mUserSetupUri;
+
+    public DeviceProvisionedControllerImpl(Context context) {
+        super(context);
+        mContext = context;
+        mContentResolver = context.getContentResolver();
+        mDeviceProvisionedUri = Global.getUriFor(Global.DEVICE_PROVISIONED);
+        mUserSetupUri = Secure.getUriFor(Secure.USER_SETUP_COMPLETE);
+    }
+
+    @Override
+    public boolean isDeviceProvisioned() {
+        return Global.getInt(mContentResolver, Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    @Override
+    public boolean isUserSetup(int currentUser) {
+        return Secure.getIntForUser(mContentResolver, Secure.USER_SETUP_COMPLETE, 0, currentUser)
+                != 0;
+    }
+
+    @Override
+    public int getCurrentUser() {
+        return ActivityManager.getCurrentUser();
+    }
+
+    @Override
+    public void addCallback(DeviceProvisionedListener listener) {
+        mListeners.add(listener);
+        if (mListeners.size() == 1) {
+            startListening(getCurrentUser());
+        }
+    }
+
+    @Override
+    public void removeCallback(DeviceProvisionedListener listener) {
+        mListeners.remove(listener);
+        if (mListeners.size() == 0) {
+            stopListening();
+        }
+    }
+
+    private void startListening(int user) {
+        mContentResolver.registerContentObserver(mDeviceProvisionedUri, true,
+                mSettingsObserver, 0);
+        mContentResolver.registerContentObserver(mUserSetupUri, true,
+                mSettingsObserver, user);
+        startTracking();
+    }
+
+    private void stopListening() {
+        stopTracking();
+        mContentResolver.unregisterContentObserver(mSettingsObserver);
+    }
+
+    @Override
+    public void onUserSwitched(int newUserId) {
+        stopListening();
+        startListening(newUserId);
+        notifyUserChanged();
+        notifyUserChanged();
+    }
+
+    private void notifyUserChanged() {
+        mListeners.forEach(c -> c.onUserSwitched());
+    }
+
+    private void notifySetupChanged() {
+        mListeners.forEach(c -> c.onUserSetupChanged());
+    }
+
+    private void notifyProvisionedChanged() {
+        mListeners.forEach(c -> c.onDeviceProvisionedChanged());
+    }
+
+    protected final ContentObserver mSettingsObserver = new ContentObserver(Dependency.get(
+            Dependency.MAIN_HANDLER)) {
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            if (mUserSetupUri.equals(uri)) {
+                notifySetupChanged();
+            } else {
+                notifyProvisionedChanged();
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 6023f3e..e576f36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -14,9 +14,10 @@
 
 package com.android.systemui.statusbar.policy;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
 
-public interface FlashlightController extends CallbackController<FlashlightListener> {
+public interface FlashlightController extends CallbackController<FlashlightListener>, Dumpable {
 
     boolean hasFlashlight();
     void setFlashlight(boolean newState);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index daf9d6b..0543678 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -16,9 +16,10 @@
 
 package com.android.systemui.statusbar.policy;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.HotspotController.Callback;
 
-public interface HotspotController extends CallbackController<Callback> {
+public interface HotspotController extends CallbackController<Callback>, Dumpable {
     boolean isHotspotEnabled();
     void setHotspotEnabled(boolean enabled);
     boolean isHotspotSupported();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 1cf4050..4b283fed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -30,6 +30,7 @@
 import android.widget.FrameLayout;
 
 import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.qs.tiles.UserDetailItemView;
@@ -56,10 +57,10 @@
     private boolean mAnimating;
 
     public KeyguardUserSwitcher(Context context, ViewStub userSwitcher,
-            KeyguardStatusBarView statusBarView, NotificationPanelView panelView,
-            UserSwitcherController userSwitcherController) {
+            KeyguardStatusBarView statusBarView, NotificationPanelView panelView) {
         boolean keyguardUserSwitcherEnabled =
                 context.getResources().getBoolean(R.bool.config_keyguardUserSwitcher) || ALWAYS_ON;
+        UserSwitcherController userSwitcherController = Dependency.get(UserSwitcherController.class);
         if (userSwitcherController != null && keyguardUserSwitcherEnabled) {
             mUserSwitcherContainer = (Container) userSwitcher.inflate();
             mBackground = new KeyguardUserSwitcherScrim(context);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 082fe82..a22fc6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -21,17 +21,18 @@
 import android.telephony.SubscriptionInfo;
 import com.android.settingslib.net.DataUsageController;
 import com.android.settingslib.wifi.AccessPoint;
+import com.android.systemui.DemoMode;
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.util.List;
 
-public interface NetworkController extends CallbackController<SignalCallback> {
+public interface NetworkController extends CallbackController<SignalCallback>, DemoMode {
 
     boolean hasMobileDataFeature();
     void addCallback(SignalCallback cb);
     void removeCallback(SignalCallback cb);
     void setWifiEnabled(boolean enabled);
-    void onUserSwitched(int newUserId);
     AccessPointController getAccessPointController();
     DataUsageController getMobileDataController();
     DataSaverController getDataSaverController();
@@ -40,6 +41,9 @@
 
     void addEmergencyListener(EmergencyListener listener);
     void removeEmergencyListener(EmergencyListener listener);
+    void setUserSetupComplete(boolean userSetup);
+    boolean hasEmergencyCryptKeeperText();
+    boolean isRadioOn();
 
     public interface SignalCallback {
         default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index a7fab41..edf2c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.NetworkCapabilities;
@@ -42,8 +43,12 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.DemoMode;
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
+import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -60,7 +65,8 @@
 
 /** Platform implementation of the network controller. **/
 public class NetworkControllerImpl extends BroadcastReceiver
-        implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider {
+        implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider,
+        ConfigurationChangedReceiver, Dumpable {
     // debug
     static final String TAG = "NetworkController";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -80,6 +86,7 @@
     private final boolean mHasMobileDataFeature;
     private final SubscriptionDefaults mSubDefaults;
     private final DataSaverController mDataSaverController;
+    private final CurrentUserTracker mUserTracker;
     private Config mConfig;
 
     // Subcontrollers.
@@ -135,7 +142,8 @@
     /**
      * Construct this controller object and register for updates.
      */
-    public NetworkControllerImpl(Context context, Looper bgLooper) {
+    public NetworkControllerImpl(Context context, Looper bgLooper,
+            DeviceProvisionedController deviceProvisionedController) {
         this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
                 (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
@@ -143,7 +151,8 @@
                 new CallbackHandler(),
                 new AccessPointControllerImpl(context, bgLooper),
                 new DataUsageController(context),
-                new SubscriptionDefaults());
+                new SubscriptionDefaults(),
+                deviceProvisionedController);
         mReceiverHandler.post(mRegisterListeners);
     }
 
@@ -154,7 +163,8 @@
             CallbackHandler callbackHandler,
             AccessPointControllerImpl accessPointController,
             DataUsageController dataUsageController,
-            SubscriptionDefaults defaultsHandler) {
+            SubscriptionDefaults defaultsHandler,
+            DeviceProvisionedController deviceProvisionedController) {
         mContext = context;
         mConfig = config;
         mReceiverHandler = new Handler(bgLooper);
@@ -191,6 +201,20 @@
 
         // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
         updateAirplaneMode(true /* force callback */);
+        mUserTracker = new CurrentUserTracker(mContext) {
+            @Override
+            public void onUserSwitched(int newUserId) {
+                NetworkControllerImpl.this.onUserSwitched(newUserId);
+            }
+        };
+        mUserTracker.startTracking();
+        deviceProvisionedController.addCallback(new DeviceProvisionedListener() {
+            @Override
+            public void onUserSetupChanged() {
+                setUserSetupComplete(deviceProvisionedController.isUserSetup(
+                        deviceProvisionedController.getCurrentUser()));
+            }
+        });
     }
 
     public DataSaverController getDataSaverController() {
@@ -358,8 +382,7 @@
         }.execute();
     }
 
-    @Override
-    public void onUserSwitched(int newUserId) {
+    private void onUserSwitched(int newUserId) {
         mCurrentUserId = newUserId;
         mAccessPoints.onUserSwitched(newUserId);
         updateConnectivity();
@@ -413,7 +436,7 @@
         }
     }
 
-    public void onConfigurationChanged() {
+    public void onConfigurationChanged(Configuration newConfig) {
         mConfig = Config.readConfig(mContext);
         mReceiverHandler.post(new Runnable() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
index e5b0c03..366a752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmController.java
@@ -16,9 +16,10 @@
 
 import android.app.AlarmManager;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
 
-public interface NextAlarmController extends CallbackController<NextAlarmChangeCallback> {
+public interface NextAlarmController extends CallbackController<NextAlarmChangeCallback>, Dumpable {
 
     public interface NextAlarmChangeCallback {
         void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index 3142228..3f8e41a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -15,9 +15,11 @@
  */
 package com.android.systemui.statusbar.policy;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
 
-public interface SecurityController extends CallbackController<SecurityControllerCallback> {
+public interface SecurityController extends CallbackController<SecurityControllerCallback>,
+        Dumpable {
     /** Whether the device has device owner, even if not on this user. */
     boolean isDeviceManaged();
     boolean hasProfileOwner();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index df959bd..19ced23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -39,12 +39,13 @@
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.systemui.R;
+import com.android.systemui.settings.CurrentUserTracker;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-public class SecurityControllerImpl implements SecurityController {
+public class SecurityControllerImpl extends CurrentUserTracker implements SecurityController {
 
     private static final String TAG = "SecurityController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -73,6 +74,7 @@
     private int mVpnUserId;
 
     public SecurityControllerImpl(Context context) {
+        super(context);
         mContext = context;
         mDevicePolicyManager = (DevicePolicyManager)
                 context.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -87,6 +89,7 @@
         // TODO: re-register network callback on user change.
         mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
         onUserSwitched(ActivityManager.getCurrentUser());
+        startTracking();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index ed8c7ff..b59cf68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -224,7 +224,7 @@
     static final int ICON_CARRIER_NETWORK_CHANGE =
             R.drawable.stat_sys_signal_carrier_network_change_animation;
 
-    static final int ICON_DATA_DISABLED = R.drawable.stat_sys_data_disabled;
+    static final int ICON_DATA_DISABLED = R.drawable.ic_qs_data_disabled;
 
     static final int QS_ICON_LTE = R.drawable.ic_qs_signal_lte;
     static final int QS_ICON_3G = R.drawable.ic_qs_signal_3g;
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 4785ba9..f71c5d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -52,13 +52,14 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.Dependency;
 import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUISecondaryUserService;
 import com.android.systemui.plugins.qs.QS.DetailAdapter;
 import com.android.systemui.qs.tiles.UserDetailView;
-import com.android.systemui.plugins.qs.QS.ActivityStarter;
+import com.android.systemui.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.io.FileDescriptor;
@@ -645,11 +646,6 @@
     }
 
     @VisibleForTesting
-    public KeyguardMonitor getKeyguardMonitor() {
-        return mKeyguardMonitor;
-    }
-
-    @VisibleForTesting
     public ArrayList<UserRecord> getUsers() {
         return mUsers;
     }
@@ -657,17 +653,19 @@
     public static abstract class BaseUserAdapter extends BaseAdapter {
 
         final UserSwitcherController mController;
+        private final KeyguardMonitor mKeyguardMonitor;
 
         protected BaseUserAdapter(UserSwitcherController controller) {
             mController = controller;
+            mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
             controller.addAdapter(new WeakReference<>(this));
         }
 
         @Override
         public int getCount() {
-            boolean secureKeyguardShowing = mController.getKeyguardMonitor().isShowing()
-                    && mController.getKeyguardMonitor().isSecure()
-                    && !mController.getKeyguardMonitor().canSkipBouncer();
+            boolean secureKeyguardShowing = mKeyguardMonitor.isShowing()
+                    && mKeyguardMonitor.isSecure()
+                    && !mKeyguardMonitor.canSkipBouncer();
             if (!secureKeyguardShowing) {
                 return mController.getUsers().size();
             }
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 bcdb62d..f195f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -30,7 +30,6 @@
     ZenRule getManualRule();
     ZenModeConfig getConfig();
     long getNextAlarm();
-    void setUserId(int userId);
     boolean isZenAvailable();
     ComponentName getEffectsSuppressor();
     boolean isCountdownConditionSupported();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 96efea1..e80d3b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -40,13 +40,14 @@
 import android.util.Slog;
 
 import com.android.systemui.qs.GlobalSetting;
+import com.android.systemui.settings.CurrentUserTracker;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.Objects;
 
 /** Platform implementation of the zen mode controller. **/
-public class ZenModeControllerImpl implements ZenModeController {
+public class ZenModeControllerImpl extends CurrentUserTracker implements ZenModeController {
     private static final String TAG = "ZenModeController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -66,6 +67,7 @@
     private ZenModeConfig mConfig;
 
     public ZenModeControllerImpl(Context context, Handler handler) {
+        super(context);
         mContext = context;
         mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
             @Override
@@ -87,6 +89,7 @@
         mSetupObserver = new SetupObserver(handler);
         mSetupObserver.register();
         mUserManager = context.getSystemService(UserManager.class);
+        startTracking();
     }
 
     @Override
@@ -137,7 +140,7 @@
     }
 
     @Override
-    public void setUserId(int userId) {
+    public void onUserSwitched(int userId) {
         mUserId = userId;
         if (mRegistered) {
             mContext.unregisterReceiver(mReceiver);
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 06cd769..395e8f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -359,6 +359,7 @@
     private boolean mInHeadsUpPinnedMode;
     private boolean mHeadsUpAnimatingAway;
     private int mStatusBarState;
+    private int mCachedBackgroundColor;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -445,8 +446,11 @@
                         + alphaInv * Color.green(scrimColor)),
                 (int) (mBackgroundFadeAmount * Color.blue(mBgColor)
                         + alphaInv * Color.blue(scrimColor)));
-        mBackgroundPaint.setColor(color);
-        invalidate();
+        if (mCachedBackgroundColor != color) {
+            mCachedBackgroundColor = color;
+            mBackgroundPaint.setColor(color);
+            invalidate();
+        }
     }
 
     private void initView(Context context) {
@@ -1879,12 +1883,16 @@
         float previousIncreasedAmount = 0.0f;
         int numShownItems = 0;
         boolean finish = false;
+        int maxDisplayedNotifications = mAmbientState.isDark()
+                ? (mPulsing ? 1 : 0)
+                : mMaxDisplayedNotifications;
+
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView expandableView = (ExpandableView) getChildAt(i);
             if (expandableView.getVisibility() != View.GONE
                     && !expandableView.hasNoContentHeight()) {
-                if (mMaxDisplayedNotifications != -1
-                        && numShownItems >= mMaxDisplayedNotifications) {
+                if (maxDisplayedNotifications != -1
+                        && numShownItems >= maxDisplayedNotifications) {
                     expandableView = mShelf;
                     finish = true;
                 }
@@ -2092,9 +2100,14 @@
      * Update the background bounds to the new desired bounds
      */
     private void updateBackgroundBounds() {
-        getLocationInWindow(mTempInt2);
-        mBackgroundBounds.left = mTempInt2[0];
-        mBackgroundBounds.right = mTempInt2[0] + getWidth();
+        if (mAmbientState.isPanelFullWidth()) {
+            mBackgroundBounds.left = 0;
+            mBackgroundBounds.right = getWidth();
+        } else {
+            getLocationInWindow(mTempInt2);
+            mBackgroundBounds.left = mTempInt2[0];
+            mBackgroundBounds.right = mTempInt2[0] + getWidth();
+        }
         if (!mIsExpanded) {
             mBackgroundBounds.top = 0;
             mBackgroundBounds.bottom = 0;
@@ -3477,6 +3490,8 @@
             updateBackground();
             setWillNotDraw(false);
         }
+        updateContentHeight();
+        notifyHeightChangeListener(mShelf);
     }
 
     private void setBackgroundFadeAmount(float fadeAmount) {
@@ -3912,6 +3927,8 @@
     public void setPulsing(boolean pulsing) {
         mPulsing = pulsing;
         updateNotificationAnimationStates();
+        updateContentHeight();
+        notifyHeightChangeListener(mShelf);
     }
 
     public void setFadingOut(boolean fadingOut) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
index 1f0ee57..36c673c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
@@ -25,7 +25,6 @@
 import java.io.PrintWriter;
 
 public interface VolumeComponent extends DemoMode {
-    ZenModeController getZenController();
     void dismissNow();
     void onConfigurationChanged(Configuration newConfig);
     void dump(FileDescriptor fd, PrintWriter pw, String[] args);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index f195a0b..137a12f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -16,20 +16,17 @@
 
 package com.android.systemui.volume;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.media.VolumePolicy;
 import android.os.Bundle;
 import android.os.Handler;
-import android.provider.Settings;
-import android.util.Log;
 import android.view.WindowManager;
 
-import com.android.systemui.R;
+import com.android.systemui.ActivityStarter;
+import com.android.systemui.Dependency;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -37,11 +34,9 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.volume.car.CarVolumeDialogController;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
 
 /**
  * Implementation of VolumeComponent backed by the new volume dialog.
@@ -69,15 +64,14 @@
             400    // vibrateToSilentDebounce
     );
 
-    public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler,
-            ZenModeController zen) {
+    public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler) {
         mSysui = sysui;
         mContext = context;
         mController = SystemUIFactory.getInstance().createVolumeDialogController(context, null);
         mController.setUserActivityListener(this);
-        mZenModeController = zen;
+        mZenModeController = Dependency.get(ZenModeController.class);
         mDialog = new VolumeDialog(context, WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY,
-                mController, zen, mVolumeDialogCallback);
+                mController, mZenModeController, mVolumeDialogCallback);
         applyConfiguration();
         TunerService.get(mContext).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT,
                 VOLUME_SILENT_DO_NOT_DISTURB);
@@ -134,11 +128,6 @@
     }
 
     @Override
-    public ZenModeController getZenController() {
-        return mZenModeController;
-    }
-
-    @Override
     public void onConfigurationChanged(Configuration newConfig) {
         // noop
     }
@@ -166,7 +155,7 @@
     }
 
     private void startSettings(Intent intent) {
-        mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(intent,
+        Dependency.get(ActivityStarter.class).startActivity(intent,
                 true /* onlyProvisioned */, true /* dismissShade */);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 73d9ea7..02969e4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -42,8 +42,7 @@
     public void start() {
         mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
         if (!mEnabled) return;
-        final ZenModeController zenController = new ZenModeControllerImpl(mContext, mHandler);
-        mVolumeComponent = new VolumeDialogComponent(this, mContext, null, zenController);
+        mVolumeComponent = new VolumeDialogComponent(this, mContext, null);
         putComponent(VolumeComponent.class, getVolumeComponent());
         setDefaultVolumeController();
     }
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index e96ea19..c627e22 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -46,7 +46,8 @@
     android-support-test \
     mockito-updated-target-minus-junit4 \
     SystemUI-proto \
-    SystemUI-tags
+    SystemUI-tags \
+    legacy-android-test
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
 
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index dec8ba6..6516369 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.systemui.tests">
 
+    <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
@@ -28,6 +29,7 @@
     <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
+    <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
new file mode 100644
index 0000000..973f1f2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.os.Looper;
+
+import com.android.systemui.statusbar.policy.FlashlightController;
+
+import org.junit.Test;
+
+public class DependencyTest extends SysuiTestCase {
+
+    @Test
+    public void testClassDependency() {
+        FlashlightController f = mock(FlashlightController.class);
+        injectTestDependency(FlashlightController.class, f);
+        assertEquals(f, Dependency.get(FlashlightController.class));
+    }
+
+    @Test
+    public void testStringDependency() {
+        Looper l = Looper.getMainLooper();
+        injectTestDependency(Dependency.BG_LOOPER, l);
+        assertEquals(l, Dependency.get(Dependency.BG_LOOPER));
+    }
+
+    @Test
+    public void testDump() {
+        Dumpable d = mock(Dumpable.class);
+        injectTestDependency("test", d);
+        Dependency.get("test");
+        mDependency.dump(null, null, null);
+        verify(d).dump(eq(null), eq(null), eq(null));
+    }
+
+    @Test
+    public void testConfigurationChanged() {
+        ConfigurationChangedReceiver d = mock(ConfigurationChangedReceiver.class);
+        injectTestDependency("test", d);
+        Dependency.get("test");
+        mDependency.onConfigurationChanged(null);
+        verify(d).onConfigurationChanged(eq(null));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index d1d7520..5fe5174 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -15,11 +15,14 @@
  */
 package com.android.systemui;
 
+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.util.ArrayMap;
 
 import com.android.systemui.utils.TestableContext;
 import com.android.systemui.utils.leaks.Tracker;
@@ -34,11 +37,15 @@
 
     private Handler mHandler;
     protected TestableContext mContext;
+    protected TestDependency mDependency;
 
     @Before
     public void SysuiSetup() throws Exception {
         System.setProperty("dexmaker.share_classloader", "true");
         mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this);
+        mDependency = new TestDependency();
+        mDependency.mContext = mContext;
+        mDependency.start();
     }
 
     @After
@@ -78,11 +85,37 @@
         return null;
     }
 
+    public void injectMockDependency(Class<?> cls) {
+        mDependency.injectTestDependency(cls.getName(), mock(cls));
+    }
+
+    public void injectTestDependency(Class<?> cls, Object obj) {
+        mDependency.injectTestDependency(cls.getName(), obj);
+    }
+
+    public void injectTestDependency(String key, Object obj) {
+        mDependency.injectTestDependency(key, obj);
+    }
+
     public static final class EmptyRunnable implements Runnable {
         public void run() {
         }
     }
 
+    public static class TestDependency extends Dependency {
+        private final ArrayMap<String, Object> mObjs = new ArrayMap<>();
+
+        private void injectTestDependency(String key, Object 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);
+        }
+    }
+
     public static final class Idler implements MessageQueue.IdleHandler {
         private final Runnable mCallback;
         private boolean mIdle;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
index be6290b..76bb6c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
@@ -150,4 +150,28 @@
         mVisualStabilityManager.onReorderingFinished();
         assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false);
     }
+
+    @Test
+    public void testPulsing() {
+        mVisualStabilityManager.setPulsing(true);
+        assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false);
+        mVisualStabilityManager.setPulsing(false);
+        assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true);
+    }
+
+    @Test
+    public void testReorderingAllowedChanges_Pulsing() {
+        mVisualStabilityManager.setPulsing(true);
+        assertEquals(mVisualStabilityManager.isReorderingAllowed(), false);
+        mVisualStabilityManager.setPulsing(false);
+        assertEquals(mVisualStabilityManager.isReorderingAllowed(), true);
+    }
+
+    @Test
+    public void testCallBackCalled_Pulsing() {
+        mVisualStabilityManager.setPulsing(true);
+        mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+        mVisualStabilityManager.setPulsing(false);
+        verify(mCallback).onReorderingAllowed();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index d529ee1..3715df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -113,8 +113,7 @@
         waitForIdleSync(mPluginInstanceManager.mPluginHandler);
         waitForIdleSync(mPluginInstanceManager.mMainHandler);
 
-        verify(mMockListener, Mockito.never()).onPluginConnected(
-                ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(mMockListener, Mockito.never()).onPluginConnected(any(), any());
     }
 
     @Test
@@ -124,7 +123,7 @@
         // Verify startup lifecycle
         verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
                 ArgumentCaptor.forClass(Context.class).capture());
-        verify(mMockListener).onPluginConnected(ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(mMockListener).onPluginConnected(any(), any());
     }
 
     @Test
@@ -154,8 +153,7 @@
         waitForIdleSync(mPluginInstanceManager.mMainHandler);
 
         // Plugin shouldn't be connected because it is the wrong version.
-        verify(mMockListener, Mockito.never()).onPluginConnected(
-                ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(mMockListener, Mockito.never()).onPluginConnected(any(), any());
         verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(SystemMessage.NOTE_PLUGIN),
                 any(), eq(UserHandle.ALL));
     }
@@ -176,8 +174,7 @@
         verify(sMockPlugin, Mockito.times(2)).onCreate(
                 ArgumentCaptor.forClass(Context.class).capture(),
                 ArgumentCaptor.forClass(Context.class).capture());
-        verify(mMockListener, Mockito.times(2)).onPluginConnected(
-                ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(mMockListener, Mockito.times(2)).onPluginConnected(any(), any());
     }
 
     @Test
@@ -193,8 +190,7 @@
         waitForIdleSync(mPluginInstanceManager.mMainHandler);;
 
         // Non-debuggable build should receive no plugins.
-        verify(mMockListener, Mockito.never()).onPluginConnected(
-                ArgumentCaptor.forClass(Plugin.class).capture());
+        verify(mMockListener, Mockito.never()).onPluginConnected(any(), any());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
index 8acd6ba..2f6487b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
@@ -29,6 +29,7 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.SecurityController;
@@ -56,6 +57,8 @@
 
     @Before
     public void setUp() {
+        injectTestDependency(SecurityController.class, mSecurityController);
+        injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
         mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
                 new LayoutInflaterBuilder(mContext)
                         .replace("ImageView", TestableImageView.class)
@@ -67,7 +70,7 @@
         mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
         mFooterIcon = (TestableImageView) mRootView.findViewById(R.id.footer_icon);
         mFooterIcon2 = (TestableImageView) mRootView.findViewById(R.id.footer_icon2);
-        mFooter.setHostEnvironment(null, mSecurityController, Looper.getMainLooper());
+        mFooter.setHostEnvironment(null);
     }
 
     @Test
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 c0d5bbd..e3ee851 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -18,11 +18,12 @@
 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.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.phone.QuickStatusBarHeader;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -42,6 +43,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -54,33 +56,24 @@
         super(QSFragment.class);
     }
 
+    @Before
+    public void addLeakCheckDependencies() {
+        injectMockDependency(UserSwitcherController.class);
+        injectLeakCheckedDependencies(BluetoothController.class, LocationController.class,
+                RotationLockController.class, NetworkController.class, ZenModeController.class,
+                HotspotController.class, CastController.class, FlashlightController.class,
+                UserInfoController.class, KeyguardMonitor.class, SecurityController.class,
+                BatteryController.class, NextAlarmController.class);
+    }
+
     @Test
     public void testListening() {
         QSFragment qs = (QSFragment) mFragment;
         postAndWait(() -> mFragments.dispatchResume());
-        UserSwitcherController userSwitcher = mock(UserSwitcherController.class);
-        KeyguardMonitor keyguardMonitor = getLeakChecker(KeyguardMonitor.class);
-        when(userSwitcher.getKeyguardMonitor()).thenReturn(keyguardMonitor);
-        when(userSwitcher.getUsers()).thenReturn(new ArrayList<>());
-        QSTileHost host = new QSTileHost(mContext,
-                null,
-                getLeakChecker(BluetoothController.class),
-                getLeakChecker(LocationController.class),
-                getLeakChecker(RotationLockController.class),
-                getLeakChecker(NetworkController.class),
-                getLeakChecker(ZenModeController.class),
-                getLeakChecker(HotspotController.class),
-                getLeakChecker(CastController.class),
-                getLeakChecker(FlashlightController.class),
-                userSwitcher,
-                getLeakChecker(UserInfoController.class),
-                keyguardMonitor,
-                getLeakChecker(SecurityController.class),
-                getLeakChecker(BatteryController.class),
-                mock(StatusBarIconController.class),
-                getLeakChecker(NextAlarmController.class));
+        QSTileHost host = new QSTileHost(mContext, null,
+                mock(StatusBarIconController.class));
         qs.setHost(host);
-        Handler h = new Handler(host.getLooper());
+        Handler h = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
 
         qs.setListening(true);
         waitForIdleSync(h);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 3ee1372..4146cb81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -47,13 +47,7 @@
     @Before
     public void setUp() throws Exception {
         mManagers = new ArrayList<>();
-        final NetworkController networkController = Mockito.mock(NetworkController.class);
-        Mockito.when(networkController.getDataSaverController()).thenReturn(
-                Mockito.mock(DataSaverController.class));
-        QSTileHost host = new QSTileHost(mContext, null, null, null, null,
-                networkController, null,
-                Mockito.mock(HotspotController.class), null,
-                null, null, null, null, null, null, null, null);
+        QSTileHost host = new QSTileHost(mContext, null, null);
         mTileService = new TestTileServices(host, Looper.getMainLooper());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
new file mode 100644
index 0000000..3bb9f5f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+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 org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationContentViewTest {
+
+    NotificationContentView mView;
+    Context mContext;
+
+    @Before
+    public void setup() {
+        ExpandableNotificationRow rowMock = mock(ExpandableNotificationRow.class);
+        when(rowMock.getIntrinsicHeight()).thenReturn(10);
+
+        mContext = InstrumentationRegistry.getTargetContext();
+        mView = new NotificationContentView(mContext, null);
+        mView.setContainingNotification(rowMock);
+        mView.setHeights(10, 20, 30, 40);
+
+        mView.setContractedChild(createViewWithHeight(10));
+        mView.setExpandedChild(createViewWithHeight(20));
+        mView.setHeadsUpChild(createViewWithHeight(30));
+        mView.setAmbientChild(createViewWithHeight(40));
+
+        mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
+    }
+
+    private View createViewWithHeight(int height) {
+        View view = new View(mContext, null);
+        view.setMinimumHeight(height);
+        return view;
+    }
+
+    @Test
+    @UiThreadTest
+    public void animationStartType_getsClearedAfterUpdatingVisibilitiesWithoutAnimation() {
+        mView.setHeadsUp(true);
+        mView.setDark(true, false, 0);
+        mView.setDark(false, true, 0);
+        mView.setHeadsUpAnimatingAway(true);
+        Assert.assertFalse(mView.isAnimatingVisibleType());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
new file mode 100644
index 0000000..7d9e073
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.statusbar;
+
+import android.graphics.drawable.Icon;
+import android.os.Debug;
+import android.os.UserHandle;
+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.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StatusBarIconViewTest extends SysuiTestCase {
+
+    private StatusBarIconView mIconView;
+    private StatusBarIcon mStatusBarIcon = mock(StatusBarIcon.class);
+
+    @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, "");
+    }
+
+    @Test
+    public void testSetClearsGrayscale() {
+        mIconView.setTag(R.id.icon_is_grayscale, true);
+        mIconView.set(mStatusBarIcon);
+        assertNull(mIconView.getTag(R.id.icon_is_grayscale));
+    }
+
+}
\ No newline at end of file
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 34743ff..9fcb5f7 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
@@ -16,12 +16,17 @@
 
 import static org.mockito.Mockito.mock;
 
+import android.content.Context;
+import android.view.WindowManager;
+
 import com.android.systemui.FragmentTestCase;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
+import org.junit.Test;
 
 public class NavigationBarFragmentTest extends FragmentTestCase {
 
@@ -37,4 +42,13 @@
         mContext.putComponent(Divider.class, mock(Divider.class));
     }
 
+    @Test
+    public void testHomeLongPress() {
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class));
+        NavigationBarFragment navigationBarFragment = (NavigationBarFragment) mFragment;
+
+        postAndWait(() -> mFragments.dispatchResume());
+        navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java
new file mode 100644
index 0000000..d82566f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.BaseStatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PhoneStatusBarTest extends SysuiTestCase {
+
+    StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    PhoneStatusBar mPhoneStatusBar;
+
+    @Before
+    public void setup() {
+        mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager.class);
+        mPhoneStatusBar = new TestablePhoneStatusBar(mStatusBarKeyguardViewManager);
+
+        doAnswer(invocation -> {
+            OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
+            onDismissAction.onDismiss();
+            return null;
+        }).when(mStatusBarKeyguardViewManager).dismissWithAction(any(), any(), anyBoolean());
+
+        doAnswer(invocation -> {
+            Runnable runnable = (Runnable) invocation.getArguments()[0];
+            runnable.run();
+            return null;
+        }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
+    }
+
+    @Test
+    public void executeRunnableDismissingKeyguard_nullRunnable_showingAndOccluded() {
+        when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true);
+
+        mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+    }
+
+    @Test
+    public void executeRunnableDismissingKeyguard_nullRunnable_showing() {
+        when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+        when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+
+        mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+    }
+
+    @Test
+    public void executeRunnableDismissingKeyguard_nullRunnable_notShowing() {
+        when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+        when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+
+        mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+    }
+
+    static class TestablePhoneStatusBar extends PhoneStatusBar {
+        public TestablePhoneStatusBar(StatusBarKeyguardViewManager man) {
+            mStatusBarKeyguardViewManager = man;
+        }
+
+        @Override
+        protected BaseStatusBar.H createHandler() {
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 6fe7768..23c635c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -118,7 +118,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
-                mMockSubDefaults);
+                mMockSubDefaults, mock(DeviceProvisionedController.class));
         setupNetworkController();
 
         // Trigger blank callbacks to always get the current state (some tests don't trigger
@@ -160,7 +160,8 @@
               = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                         mConfig, mContext.getMainLooper(), mCallbackHandler,
                         mock(AccessPointControllerImpl.class),
-                        mock(DataUsageController.class), mMockSubDefaults);
+                        mock(DataUsageController.class), mMockSubDefaults,
+                        mock(DeviceProvisionedController.class));
 
       setupNetworkController();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 4f961ab..1f7ec1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -1,5 +1,7 @@
 package com.android.systemui.statusbar.policy;
 
+import static org.mockito.Mockito.mock;
+
 import android.net.NetworkCapabilities;
 import android.os.Looper;
 import android.support.test.runner.AndroidJUnit4;
@@ -100,8 +102,9 @@
         mConfig.show4gForLte = true;
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
-                Mockito.mock(AccessPointControllerImpl.class),
-                Mockito.mock(DataUsageController.class), mMockSubDefaults);
+                mock(AccessPointControllerImpl.class),
+                mock(DataUsageController.class), mMockSubDefaults,
+                mock(DeviceProvisionedController.class));
         setupNetworkController();
 
         setupDefaultSignal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 4560aa7..1a61d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -56,7 +56,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
-                mMockSubDefaults);
+                mMockSubDefaults, mock(DeviceProvisionedController.class));
         setupNetworkController();
 
         verifyLastMobileDataIndicators(false, 0, 0);
@@ -110,7 +110,7 @@
         mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockSm,
                 mConfig, Looper.getMainLooper(), mCallbackHandler,
                 mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
-                mMockSubDefaults);
+                mMockSubDefaults, mock(DeviceProvisionedController.class));
         setupNetworkController();
 
         // No Subscriptions.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java
index 0238bf7..b118fdc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/BaseLeakChecker.java
@@ -14,9 +14,13 @@
 
 package com.android.systemui.utils.leaks;
 
+import com.android.systemui.Dumpable;
 import com.android.systemui.statusbar.policy.CallbackController;
 
-public class BaseLeakChecker<T> implements CallbackController<T> {
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class BaseLeakChecker<T> implements CallbackController<T>, Dumpable {
 
     private final Tracker mTracker;
 
@@ -37,4 +41,9 @@
     public void removeCallback(T listener) {
         mTracker.getLeakInfo(listener).clearAllocations();
     }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index fcfe9aa..5497686 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -14,11 +14,16 @@
 
 package com.android.systemui.utils.leaks;
 
+import android.os.Bundle;
+
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
         implements NetworkController {
 
@@ -42,6 +47,21 @@
     }
 
     @Override
+    public void setUserSetupComplete(boolean userSetup) {
+
+    }
+
+    @Override
+    public boolean hasEmergencyCryptKeeperText() {
+        return false;
+    }
+
+    @Override
+    public boolean isRadioOn() {
+        return false;
+    }
+
+    @Override
     public DataSaverController getDataSaverController() {
         return mDataSaverController;
     }
@@ -57,11 +77,6 @@
     }
 
     @Override
-    public void onUserSwitched(int newUserId) {
-
-    }
-
-    @Override
     public AccessPointController getAccessPointController() {
         return null;
     }
@@ -75,4 +90,9 @@
     public boolean hasVoiceCallingFeature() {
         return false;
     }
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
index 13ea385..7581363 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
@@ -53,11 +53,6 @@
     }
 
     @Override
-    public void setUserId(int userId) {
-
-    }
-
-    @Override
     public boolean isZenAvailable() {
         return false;
     }
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 728ed60..c182493 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
@@ -118,6 +118,12 @@
         mTrackers.values().forEach(Tracker::verify);
     }
 
+    public void injectLeakCheckedDependencies(Class<?>... cls) {
+        for (Class<?> c : cls) {
+            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/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk
index 7128b0d..1dea798 100644
--- a/packages/WAPPushManager/tests/Android.mk
+++ b/packages/WAPPushManager/tests/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 09b41fd..d8fb7a4 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 junit
 
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_CERTIFICATE := platform
diff --git a/preloaded-classes b/preloaded-classes
index 86cbb69..2fad5dd 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -823,11 +823,6 @@
 android.graphics.EmbossMaskFilter
 android.graphics.FontFamily
 android.graphics.FontListParser
-android.graphics.FontListParser$Alias
-android.graphics.FontListParser$Axis
-android.graphics.FontListParser$Config
-android.graphics.FontListParser$Family
-android.graphics.FontListParser$Font
 android.graphics.Insets
 android.graphics.Interpolator
 android.graphics.Interpolator$Result
@@ -1001,10 +996,6 @@
 android.hardware.input.InputDeviceIdentifier$1
 android.hardware.input.InputManager
 android.hardware.input.InputManager$InputDevicesChangedListener
-# These cannot be preloaded and need to be refactored into system server. b/17791590, b/21935130
-# android.hardware.location.ActivityRecognitionHardware
-# android.hardware.location.IActivityRecognitionHardware
-# android.hardware.location.IActivityRecognitionHardware$Stub
 android.hardware.location.ContextHubManager
 android.hardware.location.IContextHubService
 android.hardware.location.IContextHubService$Stub
@@ -1847,6 +1838,11 @@
 android.text.DynamicLayout$ChangeWatcher
 android.text.Editable
 android.text.Editable$Factory
+android.text.FontConfig
+android.text.FontConfig$Alias
+android.text.FontConfig$Axis
+android.text.FontConfig$Family
+android.text.FontConfig$Font
 android.text.GetChars
 android.text.GraphicsOperations
 android.text.Html
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index dc92f56..88bc99f 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3173,9 +3173,9 @@
 
     // These values should never appear in log outputs - they are reserved for
     // internal Tron use.
-    RESERVED_FOR_LOGBUILDER_VIEW = 757;
-    RESERVED_FOR_LOGBUILDER_CATEGORY = 758;
-    RESERVED_FOR_LOGBUILDER_TYPE = 759;
+    RESERVED_FOR_LOGBUILDER_CATEGORY = 757;
+    RESERVED_FOR_LOGBUILDER_TYPE = 758;
+    RESERVED_FOR_LOGBUILDER_SUBTYPE = 759;
 
     // ACTION: "Do not show again" was enabled in the support disclaimer and the
     // user accepted
@@ -3191,6 +3191,126 @@
     // ACTION: Clicking on any search result in Settings.
     ACTION_CLICK_SETTINGS_SEARCH_RESULT = 763;
 
+    // ACTION: Allow Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764;
+
+    // ACTION: Deny Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_DENY = 765;
+
+    // ACTION: Enable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766;
+
+    // ACTION: Disable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_DENY = 767;
+
+    // ACTION: Allow "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_ALLOW = 768;
+
+    // ACTION: Deny "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_DENY = 769;
+
+    // ACTION: Allow "Draw over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
+
+    // ACTION: Deny "Draw over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
+
+    // ACTION: Allow "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772;
+
+    // ACTION: Deny "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773;
+
+    // ACTION: Allow "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774;
+
+    // ACTION: Deny "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775;
+
+    // ACTION: Allow "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776;
+
+    // ACTION: Deny "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777;
+
+    // ACTION: "Premium SMS access" for an app - "ask user" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778;
+
+    // ACTION: "Premium SMS access" for an app - "never allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779;
+
+    // ACTION: "Premium SMS access" for an app - "always allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780;
+
+    // ACTION: Allow "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781;
+
+    // ACTION: Deny "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782;
+
+    // ACTION: Allow "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783;
+
+    // ACTION: Deny "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784;
+
+    // OPEN: Settings > Apps > Default Apps > Default browser
+    DEFAULT_BROWSER_PICKER = 785;
+
+    // OPEN: Settings > Apps > Default Apps > Default emergency app
+    DEFAULT_EMERGENCY_APP_PICKER = 786;
+
+    // OPEN: Settings > Apps > Default Apps > Default home
+    DEFAULT_HOME_PICKER = 787;
+
+    // OPEN: Settings > Apps > Default Apps > Default phone
+    DEFAULT_PHONE_PICKER = 788;
+
+    // OPEN: Settings > Apps > Default Apps > Default sms
+    DEFAULT_SMS_PICKER = 789;
+
+    // OPEN: Settings > Apps > Default Apps > Default notification assistant
+    DEFAULT_NOTIFICATION_ASSISTANT = 790;
+
+    // OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
+    DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
+
+
+    // OPEN: Settings > Apps > Default Apps > Default auto-fill app
+    DEFAULT_AUTO_FILL_PICKER = 792;
+
+    // These values should never appear in log outputs - they are reserved for
+    // internal Tron use.
+    NOTIFICATION_SINCE_CREATE_MILLIS = 793;
+    NOTIFICATION_SINCE_VISIBLE_MILLIS = 794;
+    NOTIFICATION_SINCE_UPDATE_MILLIS = 795;
+    NOTIFICATION_ID = 796;
+    NOTIFICATION_TAG = 797;
+    NOTIFICATION_SHADE_INDEX = 798;
+    RESERVED_FOR_LOGBUILDER_NAME = 799;
+
+    // OPEN: QS NFC tile shown
+    // ACTION: QS NFC tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    QS_NFC = 800;
+
+    // These values should never appear in log outputs - they are reserved for
+    // internal Tron use.
+    RESERVED_FOR_LOGBUILDER_BUCKET = 801;
+    RESERVED_FOR_LOGBUILDER_VALUE = 802;
+    RESERVED_FOR_LOGBUILDER_COUNTER = 803;
+    RESERVED_FOR_LOGBUILDER_HISTOGRAM = 804;
+    RESERVED_FOR_LOGBUILDER_TIMESTAMP = 805;
+    RESERVED_FOR_LOGBUILDER_PACKAGENAME = 806;
+
+    // ACTION: "Force stop" action on an app
+    ACTION_APP_FORCE_STOP = 807;
+
+    // OPEN: Settings > Apps > Gear > Special Access > Install other apps
+    // CATEGORY: SETTINGS
+    // OS: 8.0
+    MANAGE_EXTERNAL_SOURCES = 808;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/proto/src/task_snapshot.proto b/proto/src/task_snapshot.proto
new file mode 100644
index 0000000..c9d5c27
--- /dev/null
+++ b/proto/src/task_snapshot.proto
@@ -0,0 +1,30 @@
+/*
+ * 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 com.android.server.wm;
+
+ option java_package = "com.android.server.wm";
+ option java_outer_classname = "WindowManagerProtos";
+
+ message TaskSnapshotProto {
+     int32 orientation = 1;
+     int32 inset_left = 2;
+     int32 inset_top = 3;
+     int32 inset_right = 4;
+     int32 inset_bottom = 5;
+ }
\ No newline at end of file
diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk
index 836711b..d3fbd05 100644
--- a/sax/tests/saxtests/Android.mk
+++ b/sax/tests/saxtests/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := FrameworksSaxTests
 
 include $(BUILD_PACKAGE)
diff --git a/services/Android.mk b/services/Android.mk
index abd1459..e760fe2 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -37,8 +37,8 @@
 
 # The convention is to name each service module 'services.$(module_name)'
 LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services)) \
-    android.hidl.base@1.0-java \
-    android.hardware.biometrics.fingerprint@2.1-java
+    android.hidl.base@1.0-java-static \
+    android.hardware.biometrics.fingerprint@2.1-java-static
 
 ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
 LOCAL_EMMA_INSTRUMENT := true
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b34e4e4..ece5149 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -97,6 +97,7 @@
 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;
 
@@ -1489,6 +1490,7 @@
         mInitialized = true;
         updateLegacyCapabilitiesLocked(userState);
         updateServicesLocked(userState);
+        updateAccessibilityShortcutLocked(userState);
         updateWindowsForAccessibilityCallbackLocked(userState);
         updateAccessibilityFocusBehaviorLocked(userState);
         updateFilterKeyEventsLocked(userState);
@@ -1613,7 +1615,7 @@
         somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
         somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
-
+        somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
         return somethingChanged;
     }
 
@@ -1722,6 +1724,50 @@
         }
     }
 
+    private boolean readAccessibilityShortcutSettingLocked(UserState userState) {
+        String componentNameToEnableString = AccessibilityShortcutController
+                .getTargetServiceComponentNameString(mContext, userState.mUserId);
+        if ((componentNameToEnableString == null) || componentNameToEnableString.isEmpty()) {
+            if (userState.mServiceToEnableWithShortcut == null) {
+                return false;
+            }
+            userState.mServiceToEnableWithShortcut = null;
+            return true;
+        }
+        ComponentName componentNameToEnable =
+            ComponentName.unflattenFromString(componentNameToEnableString);
+        if (componentNameToEnable.equals(userState.mServiceToEnableWithShortcut)) {
+            return false;
+        }
+        userState.mServiceToEnableWithShortcut = componentNameToEnable;
+        return true;
+    }
+
+    /**
+     * Check if the service that will be enabled by the shortcut is installed. If it isn't,
+     * clear the value and the associated setting so a sideloaded service can't spoof the
+     * package name of the default service.
+     *
+     * @param userState
+     */
+    private void updateAccessibilityShortcutLocked(UserState userState) {
+        if (userState.mServiceToEnableWithShortcut == null) {
+            return;
+        }
+        boolean shortcutServiceIsInstalled = false;
+        for (int i = 0; i < userState.mInstalledServices.size(); i++) {
+            if (userState.mInstalledServices.get(i).getComponentName()
+                    .equals(userState.mServiceToEnableWithShortcut)) {
+                shortcutServiceIsInstalled = true;
+            }
+        }
+        if (!shortcutServiceIsInstalled) {
+            userState.mServiceToEnableWithShortcut = null;
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "", userState.mUserId);
+        }
+    }
+
     private boolean canRequestAndRequestsTouchExplorationLocked(Service service) {
         // Service not ready or cannot request the feature - well nothing to do.
         if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
@@ -1895,44 +1941,63 @@
     }
 
     /**
+     * AIDL-exposed method to be called when the accessibility shortcut is enabled. Requires
+     * permission to write secure settings, since someone with that permission can enable
+     * accessibility services themselves.
+     */
+    public void performAccessibilityShortcut() {
+        if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)
+                && (mContext.checkCallingPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+                != PackageManager.PERMISSION_GRANTED)) {
+            throw new SecurityException(
+                    "performAccessibilityShortcut requires the WRITE_SECURE_SETTINGS permission");
+        }
+        synchronized(mLock) {
+            UserState userState = getUserStateLocked(mCurrentUserId);
+            ComponentName serviceName = userState.mServiceToEnableWithShortcut;
+            if (serviceName == null) {
+                return;
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (userState.mComponentNameToServiceMap.get(serviceName) == null) {
+                    enableAccessibilityServiceLocked(serviceName, mCurrentUserId);
+                } else {
+                    disableAccessibilityServiceLocked(serviceName, mCurrentUserId);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    };
+
+    /**
      * Enables accessibility service specified by {@param componentName} for the {@param userId}.
      */
-    public void enableAccessibilityService(ComponentName componentName, int userId) {
-        synchronized(mLock) {
-            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                throw new SecurityException("only SYSTEM can call enableAccessibilityService.");
-            }
+    private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
+        SettingsStringHelper settingsHelper = new SettingsStringHelper(
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+        settingsHelper.addService(componentName);
+        settingsHelper.writeToSettings();
 
-            SettingsStringHelper settingsHelper = new SettingsStringHelper(
-                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
-            settingsHelper.addService(componentName);
-            settingsHelper.writeToSettings();
-
-            UserState userState = getUserStateLocked(userId);
-            if (userState.mEnabledServices.add(componentName)) {
-                onUserStateChangedLocked(userState);
-            }
+        UserState userState = getUserStateLocked(userId);
+        if (userState.mEnabledServices.add(componentName)) {
+            onUserStateChangedLocked(userState);
         }
     }
 
     /**
      * Disables accessibility service specified by {@param componentName} for the {@param userId}.
      */
-    public void disableAccessibilityService(ComponentName componentName, int userId) {
-        synchronized(mLock) {
-            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                throw new SecurityException("only SYSTEM can call disableAccessibility");
-            }
+    private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
+        SettingsStringHelper settingsHelper = new SettingsStringHelper(
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+        settingsHelper.deleteService(componentName);
+        settingsHelper.writeToSettings();
 
-            SettingsStringHelper settingsHelper = new SettingsStringHelper(
-                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
-            settingsHelper.deleteService(componentName);
-            settingsHelper.writeToSettings();
-
-            UserState userState = getUserStateLocked(userId);
-            if (userState.mEnabledServices.remove(componentName)) {
-                onUserStateChangedLocked(userState);
-            }
+        UserState userState = getUserStateLocked(userId);
+        if (userState.mEnabledServices.remove(componentName)) {
+            onUserStateChangedLocked(userState);
         }
     }
 
@@ -4307,6 +4372,8 @@
 
         public ComponentName mServiceChangingSoftKeyboardMode;
 
+        public ComponentName mServiceToEnableWithShortcut;
+
         public int mLastSentClientState = -1;
 
         public int mSoftKeyboardShowMode = 0;
@@ -4439,6 +4506,9 @@
         private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
 
+        private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -4467,6 +4537,8 @@
                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -4519,6 +4591,10 @@
                         notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
                         onUserStateChangedLocked(userState);
                     }
+                } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) {
+                    if (readAccessibilityShortcutSettingLocked(userState)) {
+                        onUserStateChangedLocked(userState);
+                    }
                 }
             }
         }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 87eb380..3523706 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -126,6 +126,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
 
 class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
         OnCrossProfileWidgetProvidersChangeListener {
@@ -152,6 +153,8 @@
     // Bump if the stored widgets need to be upgraded.
     private static final int CURRENT_VERSION = 1;
 
+    private static final AtomicLong REQUEST_COUNTER = new AtomicLong();
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -771,7 +774,8 @@
             LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
             for (int i = 0; i < N; i++) {
                 if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
-                    // We key the updates based on time, so that the values are sorted by time.
+                    // We key the updates based on request id, so that the values are sorted in the
+                    // order they were received.
                     int M = updatesMap.size();
                     for (int j = 0; j < M; j++) {
                         outUpdates.add(updatesMap.valueAt(j));
@@ -1854,9 +1858,9 @@
             // method with a wrong id. In that case, ignore the call.
             return;
         }
-        long requestTime = SystemClock.uptimeMillis();
+        long requestId = REQUEST_COUNTER.incrementAndGet();
         if (widget != null) {
-            widget.updateTimes.put(viewId, requestTime);
+            widget.updateRequestIds.put(viewId, requestId);
         }
         if (widget == null || widget.host == null || widget.host.zombie
                 || widget.host.callbacks == null || widget.provider == null
@@ -1867,7 +1871,7 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
-        args.arg3 = requestTime;
+        args.arg3 = requestId;
         args.argi1 = widget.appWidgetId;
         args.argi2 = viewId;
 
@@ -1878,10 +1882,10 @@
 
 
     private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, int viewId, long requestTime) {
+            int appWidgetId, int viewId, long requestId) {
         try {
             callbacks.viewDataChanged(appWidgetId, viewId);
-            host.lastWidgetUpdateTime = requestTime;
+            host.lastWidgetUpdateRequestId = requestId;
         } catch (RemoteException re) {
             // It failed; remove the callback. No need to prune because
             // we know that this host is still referenced by this instance.
@@ -1928,9 +1932,9 @@
     }
 
     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
-        long requestTime = SystemClock.uptimeMillis();
+        long requestId = REQUEST_COUNTER.incrementAndGet();
         if (widget != null) {
-            widget.updateTimes.put(ID_VIEWS_UPDATE, requestTime);
+            widget.updateRequestIds.put(ID_VIEWS_UPDATE, requestId);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -1941,7 +1945,7 @@
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
         args.arg3 = (updateViews != null) ? updateViews.clone() : null;
-        args.arg4 = requestTime;
+        args.arg4 = requestId;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
@@ -1950,10 +1954,10 @@
     }
 
     private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, RemoteViews views, long requestTime) {
+            int appWidgetId, RemoteViews views, long requestId) {
         try {
             callbacks.updateAppWidget(appWidgetId, views);
-            host.lastWidgetUpdateTime = requestTime;
+            host.lastWidgetUpdateRequestId = requestId;
         } catch (RemoteException re) {
             synchronized (mLock) {
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -1963,11 +1967,11 @@
     }
 
     private void scheduleNotifyProviderChangedLocked(Widget widget) {
-        long requestTime = SystemClock.uptimeMillis();
+        long requestId = REQUEST_COUNTER.incrementAndGet();
         if (widget != null) {
             // When the provider changes, reset everything else.
-            widget.updateTimes.clear();
-            widget.updateTimes.append(ID_PROVIDER_CHANGED, requestTime);
+            widget.updateRequestIds.clear();
+            widget.updateRequestIds.append(ID_PROVIDER_CHANGED, requestId);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -1978,7 +1982,7 @@
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
         args.arg3 = widget.provider.info;
-        args.arg4 = requestTime;
+        args.arg4 = requestId;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
@@ -1987,10 +1991,10 @@
     }
 
     private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, AppWidgetProviderInfo info, long requestTime) {
+            int appWidgetId, AppWidgetProviderInfo info, long requestId) {
         try {
             callbacks.providerChanged(appWidgetId, info);
-            host.lastWidgetUpdateTime = requestTime;
+            host.lastWidgetUpdateRequestId = requestId;
         } catch (RemoteException re) {
             synchronized (mLock){
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -3463,11 +3467,11 @@
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
                     RemoteViews views = (RemoteViews) args.arg3;
-                    long requestTime = (Long) args.arg4;
+                    long requestId = (Long) args.arg4;
                     final int appWidgetId = args.argi1;
                     args.recycle();
 
-                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestTime);
+                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestId);
                 } break;
 
                 case MSG_NOTIFY_PROVIDER_CHANGED: {
@@ -3475,11 +3479,11 @@
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
                     AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
-                    long requestTime = (Long) args.arg4;
+                    long requestId = (Long) args.arg4;
                     final int appWidgetId = args.argi1;
                     args.recycle();
 
-                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestTime);
+                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestId);
                 } break;
 
                 case MSG_NOTIFY_PROVIDERS_CHANGED: {
@@ -3495,13 +3499,13 @@
                     SomeArgs args = (SomeArgs) message.obj;
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
-                    long requestTime = (Long) args.arg3;
+                    long requestId = (Long) args.arg3;
                     final int appWidgetId = args.argi1;
                     final int viewId = args.argi2;
                     args.recycle();
 
                     handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId,
-                            requestTime);
+                            requestId);
                 } break;
             }
         }
@@ -3817,7 +3821,7 @@
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
-        long lastWidgetUpdateTime; // last time we were successfully able to send an update.
+        long lastWidgetUpdateRequestId; // request id for the last update successfully sent
 
         public int getUserId() {
             return UserHandle.getUserId(id.uid);
@@ -3844,18 +3848,18 @@
          */
         public boolean getPendingUpdatesForId(int appWidgetId,
                 LongSparseArray<PendingHostUpdate> outUpdates) {
-            long updateTime = lastWidgetUpdateTime;
+            long updateRequestId = lastWidgetUpdateRequestId;
             int N = widgets.size();
             for (int i = 0; i < N; i++) {
                 Widget widget = widgets.get(i);
                 if (widget.appWidgetId == appWidgetId) {
                     outUpdates.clear();
-                    for (int j = widget.updateTimes.size() - 1; j >= 0; j--) {
-                        long time = widget.updateTimes.valueAt(j);
-                        if (time <= updateTime) {
+                    for (int j = widget.updateRequestIds.size() - 1; j >= 0; j--) {
+                        long requestId = widget.updateRequestIds.valueAt(j);
+                        if (requestId <= updateRequestId) {
                             continue;
                         }
-                        int id = widget.updateTimes.keyAt(j);
+                        int id = widget.updateRequestIds.keyAt(j);
                         final PendingHostUpdate update;
                         switch (id) {
                             case ID_PROVIDER_CHANGED:
@@ -3869,7 +3873,7 @@
                             default:
                                 update = PendingHostUpdate.viewDataChanged(appWidgetId, id);
                         }
-                        outUpdates.put(time, update);
+                        outUpdates.put(requestId, update);
                     }
                     return true;
                 }
@@ -3951,8 +3955,8 @@
         RemoteViews maskedViews;
         Bundle options;
         Host host;
-        // timestamps for various operations
-        SparseLongArray updateTimes = new SparseLongArray(2);
+        // Request ids for various operations
+        SparseLongArray updateRequestIds = new SparseLongArray(2);
 
         @Override
         public String toString() {
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index 3de8a8b..ae21b07 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -202,7 +202,7 @@
 
         final AutoFillServiceInfo info;
         try {
-            info = new AutoFillServiceInfo(component, mUserId);
+            info = new AutoFillServiceInfo(context.getPackageManager(), component, mUserId);
         } catch (PackageManager.NameNotFoundException e) {
             Slog.w(TAG, "Auto-fill service not found: " + component, e);
             mInfo = null;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 31ecb75..7e82586 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -577,15 +577,18 @@
         public ArrayList<String> fullPackages;
         public IBackupObserver observer;
         public boolean userInitiated;
+        public boolean nonIncrementalBackup;
 
         BackupParams(IBackupTransport transport, String dirName, ArrayList<String> kvPackages,
-                ArrayList<String> fullPackages, IBackupObserver observer, boolean userInitiated) {
+                ArrayList<String> fullPackages, IBackupObserver observer, boolean userInitiated,
+                boolean nonIncrementalBackup) {
             this.transport = transport;
             this.dirName = dirName;
             this.kvPackages = kvPackages;
             this.fullPackages = fullPackages;
             this.observer = observer;
             this.userInitiated = userInitiated;
+            this.nonIncrementalBackup = nonIncrementalBackup;
         }
     }
 
@@ -794,7 +797,7 @@
                     try {
                         String dirName = transport.transportDirName();
                         PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
-                                queue, oldJournal, null, null, false);
+                                queue, oldJournal, null, null, false, false /* nonIncremental */);
                         Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
                         sendMessage(pbtMessage);
                     } catch (Exception e) {
@@ -1033,7 +1036,8 @@
                 mWakelock.acquire();
 
                 PerformBackupTask pbt = new PerformBackupTask(params.transport, params.dirName,
-                    kvQueue, null, params.observer, params.fullPackages, true);
+                        kvQueue, null, params.observer, params.fullPackages, true,
+                        params.nonIncrementalBackup);
                 Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
                 sendMessage(pbtMessage);
                 break;
@@ -2492,7 +2496,7 @@
         return token;
     }
 
-    public int requestBackup(String[] packages, IBackupObserver observer) {
+    public int requestBackup(String[] packages, IBackupObserver observer, int flags) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup");
 
         if (packages == null || packages.length < 1) {
@@ -2510,6 +2514,10 @@
         ArrayList<String> fullBackupList = new ArrayList<>();
         ArrayList<String> kvBackupList = new ArrayList<>();
         for (String packageName : packages) {
+            if (PACKAGE_MANAGER_SENTINEL.equals(packageName)) {
+                kvBackupList.add(packageName);
+                continue;
+            }
             try {
                 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
                         PackageManager.GET_SIGNATURES);
@@ -2543,9 +2551,12 @@
             sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
             return BackupManager.ERROR_TRANSPORT_ABORTED;
         }
+
+        boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0;
+
         Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
         msg.obj = new BackupParams(transport, dirName, kvBackupList, fullBackupList, observer,
-                true);
+                true, nonIncrementalBackup);
         mBackupHandler.sendMessage(msg);
         return BackupManager.SUCCESS;
     }
@@ -2673,17 +2684,20 @@
         ParcelFileDescriptor mNewState;
         int mStatus;
         boolean mFinished;
-        boolean mUserInitiated;
+        final boolean mUserInitiated;
+        final boolean mNonIncremental;
 
         public PerformBackupTask(IBackupTransport transport, String dirName,
                 ArrayList<BackupRequest> queue, File journal, IBackupObserver observer,
-                ArrayList<String> pendingFullBackups, boolean userInitiated) {
+                ArrayList<String> pendingFullBackups, boolean userInitiated,
+                boolean nonIncremental) {
             mTransport = transport;
             mOriginalQueue = queue;
             mJournal = journal;
             mObserver = observer;
             mPendingFullBackups = pendingFullBackups;
             mUserInitiated = userInitiated;
+            mNonIncremental = nonIncremental;
 
             mStateDir = new File(mBaseStateDir, dirName);
 
@@ -2748,6 +2762,10 @@
             // the way.
             mQueue = (ArrayList<BackupRequest>) mOriginalQueue.clone();
 
+            // When the transport is forcing non-incremental key/value payloads, we send the
+            // metadata only if it explicitly asks for it.
+            boolean skipPm = mNonIncremental;
+
             // The app metadata pseudopackage might also be represented in the
             // backup queue if apps have been added/removed since the last time
             // we performed a backup.  Drop it from the working queue now that
@@ -2758,6 +2776,7 @@
                         Slog.i(TAG, "Metadata in queue; eliding");
                     }
                     mQueue.remove(i);
+                    skipPm = false;
                     break;
                 }
             }
@@ -2785,22 +2804,27 @@
                     }
                 }
 
-                // The package manager doesn't have a proper <application> etc, but since
-                // it's running here in the system process we can just set up its agent
-                // directly and use a synthetic BackupRequest.  We always run this pass
-                // because it's cheap and this way we guarantee that we don't get out of
-                // step even if we're selecting among various transports at run time.
-                if (mStatus == BackupTransport.TRANSPORT_OK) {
-                    PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
-                            mPackageManager);
-                    mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
-                            IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
-                    addBackupTrace("PMBA invoke: " + mStatus);
+                if (skipPm) {
+                    Slog.d(TAG, "Skipping backup of package metadata.");
+                    executeNextState(BackupState.RUNNING_QUEUE);
+                } else {
+                    // The package manager doesn't have a proper <application> etc, but since
+                    // it's running here in the system process we can just set up its agent
+                    // directly and use a synthetic BackupRequest.  We always run this pass
+                    // because it's cheap and this way we guarantee that we don't get out of
+                    // step even if we're selecting among various transports at run time.
+                    if (mStatus == BackupTransport.TRANSPORT_OK) {
+                        PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+                                mPackageManager);
+                        mStatus = invokeAgentForBackup(PACKAGE_MANAGER_SENTINEL,
+                                IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
+                        addBackupTrace("PMBA invoke: " + mStatus);
 
-                    // Because the PMBA is a local instance, it has already executed its
-                    // backup callback and returned.  Blow away the lingering (spurious)
-                    // pending timeout message for it.
-                    mBackupHandler.removeMessages(MSG_TIMEOUT);
+                        // Because the PMBA is a local instance, it has already executed its
+                        // backup callback and returned.  Blow away the lingering (spurious)
+                        // pending timeout message for it.
+                        mBackupHandler.removeMessages(MSG_TIMEOUT);
+                    }
                 }
 
                 if (mStatus == BackupTransport.TRANSPORT_NOT_INITIALIZED) {
@@ -3066,6 +3090,7 @@
             if (DEBUG) Slog.d(TAG, "invokeAgentForBackup on " + packageName);
             addBackupTrace("invoking " + packageName);
 
+            File blankStateName = new File(mStateDir, "blank_state");
             mSavedStateName = new File(mStateDir, packageName);
             mBackupDataName = new File(mDataDir, packageName + ".data");
             mNewStateName = new File(mStateDir, packageName + ".new");
@@ -3088,9 +3113,10 @@
                 }
 
                 // In a full backup, we pass a null ParcelFileDescriptor as
-                // the saved-state "file". This is by definition an incremental,
-                // so we build a saved state file to pass.
-                mSavedState = ParcelFileDescriptor.open(mSavedStateName,
+                // the saved-state "file". For key/value backups we pass the old state if
+                // an incremental backup is required, and a blank state otherwise.
+                mSavedState = ParcelFileDescriptor.open(
+                        mNonIncremental ? blankStateName : mSavedStateName,
                         ParcelFileDescriptor.MODE_READ_ONLY |
                         ParcelFileDescriptor.MODE_CREATE);  // Make an empty file if necessary
 
@@ -3120,6 +3146,10 @@
                         e.toString());
                 agentErrorCleanup();
                 return BackupTransport.AGENT_ERROR;
+            } finally {
+                if (mNonIncremental) {
+                    blankStateName.delete();
+                }
             }
 
             // At this point the agent is off and running.  The next thing to happen will
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 312b878..d677f5e 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -338,9 +338,10 @@
     }
 
     @Override
-    public int requestBackup(String[] packages, IBackupObserver observer) throws RemoteException {
+    public int requestBackup(String[] packages, IBackupObserver observer, int flags)
+            throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.requestBackup(packages, observer) : null;
+        return (svc != null) ? svc.requestBackup(packages, observer, flags) : null;
     }
 
     @Override
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 07f14d4..cd88b85 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -25,8 +25,8 @@
     android.hardware.tv.cec@1.0-java
 
 LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2 \
-    android.hidl.base@1.0-java \
-    android.hardware.biometrics.fingerprint@2.1-java \
+    android.hidl.base@1.0-java-static \
+    android.hardware.biometrics.fingerprint@2.1-java-static \
 
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 581aa05..0e07ec0 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -504,8 +504,8 @@
             for (int i = alarms.size()-1; i >= 0; i--) {
                 Alarm alarm = alarms.get(i);
                 try {
-                    if (alarm.uid == uid && ActivityManager.getService().getAppStartMode(
-                            uid, alarm.packageName) == ActivityManager.APP_START_MODE_DISABLED) {
+                    if (alarm.uid == uid && ActivityManager.getService().isAppStartModeDisabled(
+                            uid, alarm.packageName)) {
                         alarms.remove(i);
                         didRemove = true;
                         if (alarm.alarmClock != null) {
@@ -1089,8 +1089,7 @@
                 operation, directReceiver, listenerTag, workSource, flags, alarmClock,
                 callingUid, callingPackage);
         try {
-            if (ActivityManager.getService().getAppStartMode(callingUid, callingPackage)
-                    == ActivityManager.APP_START_MODE_DISABLED) {
+            if (ActivityManager.getService().isAppStartModeDisabled(callingUid, callingPackage)) {
                 Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
                         + " -- package not allowed to start");
                 return;
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 570843e..1f62945 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -881,11 +881,9 @@
             }
             code = AppOpsManager.opToSwitch(code);
             UidState uidState = getUidStateLocked(uid, false);
-            if (uidState != null && uidState.opModes != null) {
-                final int uidMode = uidState.opModes.get(code);
-                if (uidMode != AppOpsManager.MODE_ALLOWED) {
-                    return uidMode;
-                }
+            if (uidState != null && uidState.opModes != null
+                    && uidState.opModes.indexOfKey(code) >= 0) {
+                return uidState.opModes.get(code);
             }
             Op op = getOpLocked(code, uid, resolvedPackageName, false);
             if (op == null) {
@@ -2126,6 +2124,7 @@
                 UidState uidState = mUidStates.valueAt(i);
 
                 pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
+                needSep = true;
 
                 SparseIntArray opModes = uidState.opModes;
                 if (opModes != null) {
@@ -2166,6 +2165,55 @@
                     }
                 }
             }
+            if (needSep) {
+                pw.println();
+            }
+
+            final int userRestrictionCount = mOpUserRestrictions.size();
+            for (int i = 0; i < userRestrictionCount; i++) {
+                IBinder token = mOpUserRestrictions.keyAt(i);
+                ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
+                pw.println("  User restrictions for token " + token + ":");
+
+                final int restrictionCount = restrictionState.perUserRestrictions != null
+                        ? restrictionState.perUserRestrictions.size() : 0;
+                if (restrictionCount > 0) {
+                    pw.println("      Restricted ops:");
+                    for (int j = 0; j < restrictionCount; j++) {
+                        int userId = restrictionState.perUserRestrictions.keyAt(j);
+                        boolean[] restrictedOps = restrictionState.perUserRestrictions.valueAt(j);
+                        if (restrictedOps == null) {
+                            continue;
+                        }
+                        StringBuilder restrictedOpsValue = new StringBuilder();
+                        restrictedOpsValue.append("[");
+                        final int restrictedOpCount = restrictedOps.length;
+                        for (int k = 0; k < restrictedOpCount; k++) {
+                            if (restrictedOps[k]) {
+                                if (restrictedOpsValue.length() > 1) {
+                                    restrictedOpsValue.append(", ");
+                                }
+                                restrictedOpsValue.append(AppOpsManager.opToName(k));
+                            }
+                        }
+                        restrictedOpsValue.append("]");
+                        pw.print("        "); pw.print("user: "); pw.print(userId);
+                                pw.print(" restricted ops: "); pw.println(restrictedOpsValue);
+                    }
+                }
+
+                final int excludedPackageCount = restrictionState.perUserExcludedPackages != null
+                        ? restrictionState.perUserExcludedPackages.size() : 0;
+                if (excludedPackageCount > 0) {
+                    pw.println("      Excluded packages:");
+                    for (int j = 0; j < excludedPackageCount; j++) {
+                        int userId = restrictionState.perUserExcludedPackages.keyAt(j);
+                        String[] packageNames = restrictionState.perUserExcludedPackages.valueAt(j);
+                        pw.print("        "); pw.print("user: "); pw.print(userId);
+                                pw.print(" packages: "); pw.println(Arrays.toString(packageNames));
+                    }
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0a088e9..f3f8da8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3121,10 +3121,7 @@
                 Settings.Global.TETHER_SUPPORTED, defaultVal) != 0)
                 && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
         return tetherEnabledInSettings && mUserManager.isAdminUser() &&
-                ((mTethering.getTetherableUsbRegexs().length != 0 ||
-                mTethering.getTetherableWifiRegexs().length != 0 ||
-                mTethering.getTetherableBluetoothRegexs().length != 0) &&
-                mTethering.getUpstreamIfaceTypes().length != 0);
+               mTethering.hasTetherableConfiguration();
     }
 
     @Override
@@ -5515,6 +5512,18 @@
                 }
             }
 
+            // Turn Always-on VPN off
+            if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    mKeyStore.delete(Credentials.LOCKDOWN_VPN);
+                    mLockdownEnabled = false;
+                    setLockdownTracker(null);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+
             // Turn VPN off
             VpnConfig vpnConfig = getVpnConfig(userId);
             if (vpnConfig != null) {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 9f63e30..97edb15 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -114,6 +115,7 @@
 
     private AlarmManager mAlarmManager;
     private IBatteryStats mBatteryStats;
+    private ActivityManagerInternal mLocalActivityManager;
     private PowerManagerInternal mLocalPowerManager;
     private PowerManager mPowerManager;
     private ConnectivityService mConnectivityService;
@@ -1272,6 +1274,11 @@
             DeviceIdleController.this.setAlarmsActive(active);
         }
 
+        /** Is the app on any of the power save whitelists, whether system or user? */
+        public boolean isAppOnWhitelist(int appid) {
+            return DeviceIdleController.this.isAppOnWhitelistInternal(appid);
+        }
+
         /**
          * Returns the array of app ids whitelisted by user. Take care not to
          * modify this, as it is a reference to the original copy. But the reference
@@ -1289,6 +1296,12 @@
         mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
     }
 
+    boolean isAppOnWhitelistInternal(int appid) {
+        synchronized (this) {
+            return Arrays.binarySearch(mPowerSaveWhitelistAllAppIdArray, appid) >= 0;
+        }
+    }
+
     int[] getPowerSaveWhitelistUserAppIds() {
         synchronized (this) {
             return mPowerSaveWhitelistUserAppIdArray;
@@ -1362,6 +1375,7 @@
             synchronized (this) {
                 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
                 mBatteryStats = BatteryStatsService.getService();
+                mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
                 mLocalPowerManager = getLocalService(PowerManagerInternal.class);
                 mPowerManager = getContext().getSystemService(PowerManager.class);
                 mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -1431,6 +1445,7 @@
                 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
                 getContext().registerReceiver(mReceiver, filter);
 
+                mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
                 mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
                 mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
                 mDisplayManager.registerDisplayListener(mDisplayListener, null);
@@ -1652,7 +1667,7 @@
                 } catch (RemoteException e) {
                 }
                 postTempActiveTimeoutMessage(appId, duration);
-                updateTempWhitelistAppIdsLocked();
+                updateTempWhitelistAppIdsLocked(appId, true);
                 if (mNetworkPolicyTempWhitelistCallback != null) {
                     if (!sync) {
                         mHandler.post(mNetworkPolicyTempWhitelistCallback);
@@ -1698,7 +1713,7 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
                 }
-                updateTempWhitelistAppIdsLocked();
+                updateTempWhitelistAppIdsLocked(uid, false);
                 if (mNetworkPolicyTempWhitelistCallback != null) {
                     mHandler.post(mNetworkPolicyTempWhitelistCallback);
                 }
@@ -2318,6 +2333,13 @@
                 mPowerSaveWhitelistUserApps, mPowerSaveWhitelistAllAppIds);
         mPowerSaveWhitelistUserAppIdArray = buildAppIdArray(null,
                 mPowerSaveWhitelistUserApps, mPowerSaveWhitelistUserAppIds);
+        if (mLocalActivityManager != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting activity manager whitelist to "
+                        + Arrays.toString(mPowerSaveWhitelistAllAppIdArray));
+            }
+            mLocalActivityManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
+        }
         if (mLocalPowerManager != null) {
             if (DEBUG) {
                 Slog.d(TAG, "Setting wakelock whitelist to "
@@ -2334,7 +2356,7 @@
         }
     }
 
-    private void updateTempWhitelistAppIdsLocked() {
+    private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
         final int size = mTempWhitelistAppIdEndTimes.size();
         if (mTempWhitelistAppIdArray.length != size) {
             mTempWhitelistAppIdArray = new int[size];
@@ -2342,6 +2364,14 @@
         for (int i = 0; i < size; i++) {
             mTempWhitelistAppIdArray[i] = mTempWhitelistAppIdEndTimes.keyAt(i);
         }
+        if (mLocalActivityManager != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting activity manager temp whitelist to "
+                        + Arrays.toString(mTempWhitelistAppIdArray));
+            }
+            mLocalActivityManager.updateDeviceIdleTempWhitelist(mTempWhitelistAppIdArray, appId,
+                    adding);
+        }
         if (mLocalPowerManager != null) {
             if (DEBUG) {
                 Slog.d(TAG, "Setting wakelock temp whitelist to "
@@ -2512,8 +2542,9 @@
         pw.println("    Add (prefix with +) or remove (prefix with -) packages.");
         pw.println("  tempwhitelist");
         pw.println("    Print packages that are temporarily whitelisted.");
-        pw.println("  tempwhitelist [-u] [package ..]");
-        pw.println("    Temporarily place packages in whitelist for 10 seconds.");
+        pw.println("  tempwhitelist [-u USER] [-d DURATION] [package ..]");
+        pw.println("    Temporarily place packages in whitelist for DURATION milliseconds.");
+        pw.println("    If no DURATION is specified, 10 seconds is used");
     }
 
     class Shell extends ShellCommand {
@@ -2796,6 +2827,7 @@
                 }
             }
         } else if ("tempwhitelist".equals(cmd)) {
+            long duration = 10000;
             String opt;
             while ((opt=shell.getNextOption()) != null) {
                 if ("-u".equals(opt)) {
@@ -2805,12 +2837,19 @@
                         return -1;
                     }
                     shell.userId = Integer.parseInt(opt);
+                } else if ("-d".equals(opt)) {
+                    opt = shell.getNextArg();
+                    if (opt == null) {
+                        pw.println("-d requires a duration");
+                        return -1;
+                    }
+                    duration = Long.parseLong(opt);
                 }
             }
             String arg = shell.getNextArg();
             if (arg != null) {
                 try {
-                    addPowerSaveTempWhitelistAppChecked(arg, 10000L, shell.userId, "shell");
+                    addPowerSaveTempWhitelistAppChecked(arg, duration, shell.userId, "shell");
                 } catch (RemoteException re) {
                     pw.println("Failed: " + re);
                 }
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index dd95f67..1bdff6b 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -22,13 +22,20 @@
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.os.storage.StorageManager;
+import android.service.diskstats.DiskStatsAppSizesProto;
+import android.service.diskstats.DiskStatsCachedValuesProto;
+import android.service.diskstats.DiskStatsFreeSpaceProto;
+import android.service.diskstats.DiskStatsServiceDumpProto;
 import android.util.Log;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.server.storage.DiskStatsFileLogger;
 import com.android.server.storage.DiskStatsLoggingService;
 
 import libcore.io.IoUtils;
 
+import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
@@ -78,32 +85,68 @@
         long after = SystemClock.uptimeMillis();
         if (tmp.exists()) tmp.delete();
 
-        if (error != null) {
-            pw.print("Test-Error: ");
-            pw.println(error.toString());
+        boolean protoFormat = hasOption(args, "--proto");
+        ProtoOutputStream proto = null;
+
+        if (protoFormat) {
+            proto = new ProtoOutputStream(fd);
+            pw = null;
+            proto.write(DiskStatsServiceDumpProto.HAS_TEST_ERROR, error != null);
+            if (error != null) {
+                proto.write(DiskStatsServiceDumpProto.ERROR_MESSAGE, error.toString());
+            } else {
+                proto.write(DiskStatsServiceDumpProto.WRITE_512B_LATENCY_MILLIS, after - before);
+            }
         } else {
-            pw.print("Latency: ");
-            pw.print(after - before);
-            pw.println("ms [512B Data Write]");
+            if (error != null) {
+                pw.print("Test-Error: ");
+                pw.println(error.toString());
+            } else {
+                pw.print("Latency: ");
+                pw.print(after - before);
+                pw.println("ms [512B Data Write]");
+            }
         }
 
-        reportFreeSpace(Environment.getDataDirectory(), "Data", pw);
-        reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
-        reportFreeSpace(new File("/system"), "System", pw);
+        reportFreeSpace(Environment.getDataDirectory(), "Data", pw, proto,
+                DiskStatsFreeSpaceProto.FOLDER_DATA);
+        reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw, proto,
+                DiskStatsFreeSpaceProto.FOLDER_CACHE);
+        reportFreeSpace(new File("/system"), "System", pw, proto,
+                DiskStatsFreeSpaceProto.FOLDER_SYSTEM);
 
-        if (StorageManager.isFileEncryptedNativeOnly()) {
+        boolean fileBased = StorageManager.isFileEncryptedNativeOnly();
+        boolean blockBased = fileBased ? false : StorageManager.isBlockEncrypted();
+        if (protoFormat) {
+            if (fileBased) {
+                proto.write(DiskStatsServiceDumpProto.ENCRYPTION,
+                        DiskStatsServiceDumpProto.ENCRYPTION_FILE_BASED);
+            } else if (blockBased) {
+                proto.write(DiskStatsServiceDumpProto.ENCRYPTION,
+                        DiskStatsServiceDumpProto.ENCRYPTION_FULL_DISK);
+            } else {
+                proto.write(DiskStatsServiceDumpProto.ENCRYPTION,
+                        DiskStatsServiceDumpProto.ENCRYPTION_NONE);
+            }
+        } else if (fileBased) {
             pw.println("File-based Encryption: true");
         }
 
-        if (isCheckin(args)) {
+        if (protoFormat) {
+            reportCachedValuesProto(proto);
+        } else {
             reportCachedValues(pw);
         }
 
+        if (protoFormat) {
+            proto.flush();
+        }
         // TODO: Read /proc/yaffs and report interesting values;
         // add configurable (through args) performance test parameters.
     }
 
-    private void reportFreeSpace(File path, String name, PrintWriter pw) {
+    private void reportFreeSpace(File path, String name, PrintWriter pw,
+            ProtoOutputStream proto, int folderType) {
         try {
             StatFs statfs = new StatFs(path.getPath());
             long bsize = statfs.getBlockSize();
@@ -114,31 +157,44 @@
                         "Invalid stat: bsize=" + bsize + " avail=" + avail + " total=" + total);
             }
 
-            pw.print(name);
-            pw.print("-Free: ");
-            pw.print(avail * bsize / 1024);
-            pw.print("K / ");
-            pw.print(total * bsize / 1024);
-            pw.print("K total = ");
-            pw.print(avail * 100 / total);
-            pw.println("% free");
+            if (proto != null) {
+                long freeSpaceToken = proto.start(DiskStatsServiceDumpProto.PARTITIONS_FREE_SPACE);
+                proto.write(DiskStatsFreeSpaceProto.FOLDER, folderType);
+                proto.write(DiskStatsFreeSpaceProto.AVAILABLE_SPACE, avail * bsize / 1024);
+                proto.write(DiskStatsFreeSpaceProto.TOTAL_SPACE, total * bsize / 1024);
+                proto.end(freeSpaceToken);
+            } else {
+                pw.print(name);
+                pw.print("-Free: ");
+                pw.print(avail * bsize / 1024);
+                pw.print("K / ");
+                pw.print(total * bsize / 1024);
+                pw.print("K total = ");
+                pw.print(avail * 100 / total);
+                pw.println("% free");
+            }
         } catch (IllegalArgumentException e) {
-            pw.print(name);
-            pw.print("-Error: ");
-            pw.println(e.toString());
+            if (proto != null) {
+                // Empty proto
+            } else {
+                pw.print(name);
+                pw.print("-Error: ");
+                pw.println(e.toString());
+            }
             return;
         }
     }
 
-    private boolean isCheckin(String[] args) {
+    private boolean hasOption(String[] args, String arg) {
         for (String opt : args) {
-            if ("--checkin".equals(opt)) {
+            if (arg.equals(opt)) {
                 return true;
             }
         }
         return false;
     }
 
+    // If you change this method, make sure to modify the Proto version of this method as well.
     private void reportCachedValues(PrintWriter pw) {
         try {
             String jsonString = IoUtils.readFileAsString(DISKSTATS_DUMP_FILE);
@@ -170,4 +226,52 @@
         }
     }
 
+    private void reportCachedValuesProto(ProtoOutputStream proto) {
+        try {
+            String jsonString = IoUtils.readFileAsString(DISKSTATS_DUMP_FILE);
+            JSONObject json = new JSONObject(jsonString);
+            long cachedValuesToken = proto.start(DiskStatsServiceDumpProto.CACHED_FOLDER_SIZES);
+
+            proto.write(DiskStatsCachedValuesProto.AGG_APPS_SIZE,
+                    json.getLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY));
+            proto.write(DiskStatsCachedValuesProto.AGG_APPS_CACHE_SIZE,
+                    json.getLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY));
+            proto.write(DiskStatsCachedValuesProto.PHOTOS_SIZE,
+                    json.getLong(DiskStatsFileLogger.PHOTOS_KEY));
+            proto.write(DiskStatsCachedValuesProto.VIDEOS_SIZE,
+                    json.getLong(DiskStatsFileLogger.VIDEOS_KEY));
+            proto.write(DiskStatsCachedValuesProto.AUDIO_SIZE,
+                    json.getLong(DiskStatsFileLogger.AUDIO_KEY));
+            proto.write(DiskStatsCachedValuesProto.DOWNLOADS_SIZE,
+                    json.getLong(DiskStatsFileLogger.DOWNLOADS_KEY));
+            proto.write(DiskStatsCachedValuesProto.SYSTEM_SIZE,
+                    json.getLong(DiskStatsFileLogger.SYSTEM_KEY));
+            proto.write(DiskStatsCachedValuesProto.OTHER_SIZE,
+                    json.getLong(DiskStatsFileLogger.MISC_KEY));
+
+            JSONArray packageNamesArray = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY);
+            JSONArray appSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY);
+            JSONArray cacheSizesArray = json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY);
+            final int len = packageNamesArray.length();
+            if (len == appSizesArray.length() && len == cacheSizesArray.length()) {
+                for (int i = 0; i < len; i++) {
+                    long packageToken = proto.start(DiskStatsCachedValuesProto.APP_SIZES);
+
+                    proto.write(DiskStatsAppSizesProto.PACKAGE_NAME,
+                            packageNamesArray.getString(i));
+                    proto.write(DiskStatsAppSizesProto.APP_SIZE, appSizesArray.getLong(i));
+                    proto.write(DiskStatsAppSizesProto.CACHE_SIZE, cacheSizesArray.getLong(i));
+
+                    proto.end(packageToken);
+                }
+            } else {
+                Slog.wtf(TAG, "Sizes of packageNamesArray, appSizesArray and cacheSizesArray "
+                        + "are not the same");
+            }
+
+            proto.end(cachedValuesToken);
+        } catch (IOException | JSONException e) {
+            Log.w(TAG, "exception reading diskstats cache file", e);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index d42fe11..4559254 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -99,6 +99,13 @@
 2810 watchdog_vmstat (runtime|2|3),(pgfree|1|1),(pgactivate|1|1),(pgdeactivate|1|1),(pgfault|1|1),(pgmajfault|1|1)
 2811 watchdog_requested_reboot (NoWait|1|1),(ScheduleInterval|1|3),(RecheckInterval|1|3),(StartTime|1|3),(Window|1|3),(MinScreenOff|1|3),(MinNextAlarm|1|3)
 
+# ---------------------------
+# RescueParty.java
+# ---------------------------
+2900 rescue_note (uid|1),(count|1),(window|2)
+2901 rescue_level (level|1),(trigger_uid|1)
+2902 rescue_success (level|1)
+2903 rescue_failure (level|1),(msg|3)
 
 # ---------------------------
 # BackupManagerService.java
diff --git a/services/core/java/com/android/server/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java
new file mode 100644
index 0000000..593c322
--- /dev/null
+++ b/services/core/java/com/android/server/FontManagerService.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 com.android.server;
+
+import android.content.Context;
+import android.graphics.FontListParser;
+import android.os.ParcelFileDescriptor;
+import android.text.FontConfig;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.font.IFontManager;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+public class FontManagerService extends IFontManager.Stub {
+    private static final String TAG = "FontManagerService";
+    private static final String FONTS_CONFIG = "/system/etc/fonts.xml";
+
+    @GuardedBy("mLock")
+    private FontConfig mConfig;
+    private final Object mLock = new Object();
+
+    public static final class Lifecycle extends SystemService {
+        private final FontManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new FontManagerService();
+        }
+
+        @Override
+        public void onStart() {
+            try {
+                publishBinderService(Context.FONT_SERVICE, mService);
+            } catch (Throwable t) {
+                // Starting this service is not critical to the running of this device and should
+                // therefore not crash the device. If it fails, log the error and continue.
+                Slog.e(TAG, "Could not start the FontManagerService.", t);
+            }
+        }
+    }
+
+    @Override
+    public FontConfig getSystemFonts() {
+        synchronized (mLock) {
+            if (mConfig != null) {
+                return new FontConfig(mConfig);
+            }
+
+            FontConfig config = loadFromSystem();
+            if (config == null) {
+                return null;
+            }
+
+            final int size = config.getFamilies().size();
+            for (int i = 0; i < size; ++i) {
+                FontConfig.Family family = config.getFamilies().get(i);
+                for (int j = 0; j < family.getFonts().size(); ++j) {
+                    FontConfig.Font font = family.getFonts().get(j);
+                    File fontFile = new File(font.getFontName());
+                    try {
+                        font.setFd(ParcelFileDescriptor.open(
+                                fontFile, ParcelFileDescriptor.MODE_READ_ONLY));
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Error opening font file " + font.getFontName(), e);
+                    }
+                }
+            }
+
+            mConfig = config;
+            return new FontConfig(mConfig);
+        }
+    }
+
+    private FontConfig loadFromSystem() {
+        File configFilename = new File(FONTS_CONFIG);
+        try {
+            FileInputStream fontsIn = new FileInputStream(configFilename);
+            return FontListParser.parse(fontsIn);
+        } catch (IOException | XmlPullParserException e) {
+            Slog.e(TAG, "Error opening " + configFilename, e);
+        }
+        return null;
+    }
+
+    public FontManagerService() {
+    }
+}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index f718fa1..bee1f97 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -243,7 +243,6 @@
     private PendingIntent mImeSwitchPendingIntent;
     private boolean mShowOngoingImeSwitcherForPhones;
     private boolean mNotificationShown;
-    private final boolean mImeSelectedOnBoot;
 
     static class SessionState {
         final ClientState client;
@@ -566,7 +565,7 @@
         }
     }
 
-    class ImmsBroadcastReceiver extends android.content.BroadcastReceiver {
+    class ImmsBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
@@ -587,6 +586,10 @@
                             Intent.EXTRA_SETTING_NEW_VALUE);
                     restoreEnabledInputMethods(mContext, prevValue, newValue);
                 }
+            } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+                synchronized (mMethodMap) {
+                    resetStateIfCurrentLocaleChangedLocked();
+                }
             } else {
                 Slog.w(TAG, "Unexpected intent " + intent);
             }
@@ -845,9 +848,11 @@
                 return;
             }
             mSettings.switchCurrentUser(currentUserId, !mSystemReady);
-            // We need to rebuild IMEs.
-            buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
-            updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+            if (mSystemReady) {
+                // We need to rebuild IMEs.
+                buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
+                updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+            }
         }
     }
 
@@ -897,13 +902,6 @@
 
         mShowOngoingImeSwitcherForPhones = false;
 
-        final IntentFilter broadcastFilter = new IntentFilter();
-        broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-        broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
-        broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
-        broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
-        mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
-
         mNotificationShown = false;
         int userId = 0;
         try {
@@ -911,7 +909,6 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
         }
-        mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
 
         // mSettings should be created before buildInputMethodListLocked
         mSettings = new InputMethodSettings(
@@ -919,48 +916,8 @@
 
         updateCurrentProfileIds();
         mFileManager = new InputMethodFileManager(mMethodMap, userId);
-        synchronized (mMethodMap) {
-            mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
-                    mSettings, context);
-        }
-
-        // Just checking if defaultImiId is empty or not
-        final String defaultImiId = mSettings.getSelectedInputMethod();
-        if (DEBUG) {
-            Slog.d(TAG, "Initial default ime = " + defaultImiId);
-        }
-        mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
-
-        synchronized (mMethodMap) {
-            buildInputMethodListLocked(!mImeSelectedOnBoot /* resetDefaultEnabledIme */);
-        }
-        mSettings.enableAllIMEsIfThereIsNoEnabledIME();
-
-        if (!mImeSelectedOnBoot) {
-            Slog.w(TAG, "No IME selected. Choose the most applicable IME.");
-            synchronized (mMethodMap) {
-                resetDefaultImeLocked(context);
-            }
-        }
-
-        synchronized (mMethodMap) {
-            mSettingsObserver.registerContentObserverLocked(userId);
-            updateFromSettingsLocked(true);
-        }
-
-        // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME
-        // according to the new system locale.
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-        mContext.registerReceiver(
-                new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        synchronized(mMethodMap) {
-                            resetStateIfCurrentLocaleChangedLocked();
-                        }
-                    }
-                }, filter);
+        mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
+                mSettings, context);
     }
 
     private void resetDefaultImeLocked(Context context) {
@@ -1089,6 +1046,7 @@
             }
             if (!mSystemReady) {
                 mSystemReady = true;
+                mLastSystemLocales = mRes.getConfiguration().getLocales();
                 final int currentUserId = mSettings.getCurrentUserId();
                 mSettings.switchCurrentUser(currentUserId,
                         !mUserManager.isUserUnlockingOrUnlocked(currentUserId));
@@ -1105,14 +1063,25 @@
                     mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
                             mHardKeyboardListener);
                 }
-                if (!mImeSelectedOnBoot) {
-                    Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
-                    resetStateIfCurrentLocaleChangedLocked();
-                    InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
-                            mSettings.getEnabledInputMethodListLocked(),
-                            mSettings.getCurrentUserId(), mContext.getBasePackageName());
-                }
-                mLastSystemLocales = mRes.getConfiguration().getLocales();
+
+                mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+                mSettingsObserver.registerContentObserverLocked(currentUserId);
+
+                final IntentFilter broadcastFilter = new IntentFilter();
+                broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+                broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
+                broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
+                broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
+                broadcastFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+                mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
+
+                buildInputMethodListLocked(true /* resetDefaultEnabledIme */);
+                resetDefaultImeLocked(mContext);
+                updateFromSettingsLocked(true);
+                InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
+                        mSettings.getEnabledInputMethodListLocked(), currentUserId,
+                        mContext.getBasePackageName());
+
                 try {
                     startInputInnerLocked();
                 } catch (RuntimeException e) {
@@ -2624,6 +2593,9 @@
         // additional input method subtypes to the IME.
         if (TextUtils.isEmpty(imiId) || subtypes == null) return;
         synchronized (mMethodMap) {
+            if (!mSystemReady) {
+                return;
+            }
             final InputMethodInfo imi = mMethodMap.get(imiId);
             if (imi == null) return;
             final String[] packageInfos;
@@ -3048,6 +3020,10 @@
             Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
                     + " \n ------ caller=" + Debug.getCallers(10));
         }
+        if (!mSystemReady) {
+            Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
+            return;
+        }
         mMethodList.clear();
         mMethodMap.clear();
 
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c9b59ade..6cc72de 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.app.ActivityManager;
 import android.content.pm.PackageManagerInternal;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
@@ -138,6 +139,9 @@
     // The maximum interval a location request can have and still be considered "high power".
     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 = 30 * 1000;
+
     // Location Providers may sometimes deliver location updates
     // slightly faster that requested - provide grace period so
     // we don't unnecessarily filter events that are otherwise on
@@ -157,6 +161,7 @@
     private GeofenceManager mGeofenceManager;
     private PackageManager mPackageManager;
     private PowerManager mPowerManager;
+    private ActivityManager mActivityManager;
     private UserManager mUserManager;
     private GeocoderProxy mGeocodeProvider;
     private IGnssStatusProvider mGnssStatusProvider;
@@ -171,47 +176,47 @@
     // --- fields below are protected by mLock ---
     // Set of providers that are explicitly enabled
     // Only used by passive, fused & test.  Network & GPS are controlled separately, and not listed.
-    private final Set<String> mEnabledProviders = new HashSet<String>();
+    private final Set<String> mEnabledProviders = new HashSet<>();
 
     // Set of providers that are explicitly disabled
-    private final Set<String> mDisabledProviders = new HashSet<String>();
+    private final Set<String> mDisabledProviders = new HashSet<>();
 
     // Mock (test) providers
     private final HashMap<String, MockProvider> mMockProviders =
-            new HashMap<String, MockProvider>();
+            new HashMap<>();
 
     // all receivers
-    private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
+    private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
 
     // currently installed providers (with mocks replacing real providers)
     private final ArrayList<LocationProviderInterface> mProviders =
-            new ArrayList<LocationProviderInterface>();
+            new ArrayList<>();
 
     // real providers, saved here when mocked out
     private final HashMap<String, LocationProviderInterface> mRealProviders =
-            new HashMap<String, LocationProviderInterface>();
+            new HashMap<>();
 
     // mapping from provider name to provider
     private final HashMap<String, LocationProviderInterface> mProvidersByName =
-            new HashMap<String, LocationProviderInterface>();
+            new HashMap<>();
 
     // mapping from provider name to all its UpdateRecords
     private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
-            new HashMap<String, ArrayList<UpdateRecord>>();
+            new HashMap<>();
 
     private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
 
     // mapping from provider name to last known location
-    private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
+    private final HashMap<String, Location> mLastLocation = new HashMap<>();
 
     // same as mLastLocation, but is not updated faster than LocationFudger.FASTEST_INTERVAL_MS.
     // locations stored here are not fudged for coarse permissions.
     private final HashMap<String, Location> mLastLocationCoarseInterval =
-            new HashMap<String, Location>();
+            new HashMap<>();
 
     // all providers that operate over proxy, for authorizing incoming location
     private final ArrayList<LocationProviderProxy> mProxyProviders =
-            new ArrayList<LocationProviderProxy>();
+            new ArrayList<>();
 
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -252,6 +257,10 @@
             // fetch power manager
             mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
 
+            // fetch activity manager
+            mActivityManager
+                    = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+
             // prepare worker thread
             mLocationHandler = new LocationWorkerHandler(BackgroundThread.get().getLooper());
 
@@ -286,6 +295,40 @@
             };
             mPackageManager.addOnPermissionsChangeListener(permissionListener);
 
+            // listen for background/foreground changes
+            ActivityManager.OnUidImportanceListener uidImportanceListener
+                    = new ActivityManager.OnUidImportanceListener() {
+                @Override
+                public void onUidImportance(int uid, int importance) {
+                    boolean foreground = isImportanceForeground(importance);
+                    HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
+                    synchronized (mLock) {
+                        for (Map.Entry<String, ArrayList<UpdateRecord>> entry
+                                : mRecordsByProvider.entrySet()) {
+                            String provider = entry.getKey();
+                            for (UpdateRecord record : entry.getValue()) {
+                                if (record.mReceiver.mUid == uid
+                                        && record.mIsForegroundUid != foreground) {
+                                    if (D) Log.d(TAG, "request from uid " + uid + " is now "
+                                            + (foreground ? "foreground" : "background)"));
+                                    record.mIsForegroundUid = foreground;
+
+                                    if (!isThrottlingExemptLocked(record.mReceiver)) {
+                                        affectedProviders.add(provider);
+                                    }
+                                }
+                            }
+                        }
+                        for (String provider : affectedProviders) {
+                            applyRequirementsLocked(provider);
+                        }
+                    }
+
+                }
+            };
+            mActivityManager.addOnUidImportanceListener(uidImportanceListener,
+                    ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE);
+
             mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
             updateUserProfiles(mCurrentUserId);
 
@@ -305,6 +348,17 @@
                         }
                     }
                 }, UserHandle.USER_ALL);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS),
+                true,
+                new ContentObserver(mLocationHandler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        synchronized (mLock) {
+                            updateProvidersLocked();
+                        }
+                    }
+                }, UserHandle.USER_ALL);
         mPackageMonitor.register(mContext, mLocationHandler.getLooper(), true);
 
         // listen for user change
@@ -334,6 +388,10 @@
         }, UserHandle.ALL, intentFilter, null, mLocationHandler);
     }
 
+    private static boolean isImportanceForeground(int importance) {
+        return importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+    }
+
     /**
      * Provides a way for components held by the {@link LocationManagerService} to clean-up
      * gracefully on system's shutdown.
@@ -483,7 +541,7 @@
         that matches the signature of at least one package on this list.
         */
         Resources resources = mContext.getResources();
-        ArrayList<String> providerPackageNames = new ArrayList<String>();
+        ArrayList<String> providerPackageNames = new ArrayList<>();
         String[] pkgs = resources.getStringArray(
                 com.android.internal.R.array.config_locationProviderPackageNames);
         if (D) Log.d(TAG, "certificates for location providers pulled from: " +
@@ -651,7 +709,7 @@
         final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
         final Object mKey;
 
-        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
+        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<>();
 
         // True if app ops has started monitoring this receiver for locations.
         boolean mOpMonitoring;
@@ -691,10 +749,7 @@
 
         @Override
         public boolean equals(Object otherObj) {
-            if (otherObj instanceof Receiver) {
-                return mKey.equals(((Receiver)otherObj).mKey);
-            }
-            return false;
+            return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
         }
 
         @Override
@@ -1011,13 +1066,25 @@
         mProvidersByName.remove(provider.getName());
     }
 
+    private boolean isOverlayProviderPackageLocked(String packageName) {
+        for (LocationProviderInterface provider : mProviders) {
+            if (provider instanceof LocationProviderProxy) {
+                if (packageName.equals(
+                        ((LocationProviderProxy) provider).getConnectedPackageName())) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
     /**
      * Returns "true" if access to the specified location provider is allowed by the current
      * user's settings. Access to all location providers is forbidden to non-location-provider
      * processes belonging to background users.
      *
      * @param provider the name of the location provider
-     * @return
      */
     private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
         if (mEnabledProviders.contains(provider)) {
@@ -1039,7 +1106,6 @@
      *
      * @param provider the name of the location provider
      * @param uid the requestor's UID
-     * @return
      */
     private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
         if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
@@ -1197,11 +1263,7 @@
             }
         }
 
-        if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
-            return false;
-        }
-
-        return true;
+        return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
     }
 
     boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
@@ -1212,11 +1274,7 @@
             }
         }
 
-        if (getAllowedResolutionLevel(pid, uid) < allowedResolutionLevel) {
-            return false;
-        }
-
-        return true;
+        return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
     }
 
     /**
@@ -1228,7 +1286,7 @@
     public List<String> getAllProviders() {
         ArrayList<String> out;
         synchronized (mLock) {
-            out = new ArrayList<String>(mProviders.size());
+            out = new ArrayList<>(mProviders.size());
             for (LocationProviderInterface provider : mProviders) {
                 String name = provider.getName();
                 if (LocationManager.FUSED_PROVIDER.equals(name)) {
@@ -1251,11 +1309,11 @@
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
         int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         ArrayList<String> out;
-        int uid = Binder.getCallingUid();;
+        int uid = Binder.getCallingUid();
         long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                out = new ArrayList<String>(mProviders.size());
+                out = new ArrayList<>(mProviders.size());
                 for (LocationProviderInterface provider : mProviders) {
                     String name = provider.getName();
                     if (LocationManager.FUSED_PROVIDER.equals(name)) {
@@ -1370,14 +1428,12 @@
 
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
         if (records != null) {
-            final int N = records.size();
-            for (int i = 0; i < N; i++) {
-                UpdateRecord record = records.get(i);
+            for (UpdateRecord record : records) {
                 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
                     // Sends a notification message to the receiver
                     if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
                         if (deadReceivers == null) {
-                            deadReceivers = new ArrayList<Receiver>();
+                            deadReceivers = new ArrayList<>();
                         }
                         deadReceivers.add(record.mReceiver);
                     }
@@ -1410,6 +1466,12 @@
         WorkSource worksource = new WorkSource();
         ProviderRequest providerRequest = new ProviderRequest();
 
+        ContentResolver resolver = mContext.getContentResolver();
+        long backgroundThrottleInterval = Settings.Global.getLong(
+                resolver,
+                Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
+                DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
+
         if (records != null) {
             for (UpdateRecord record : records) {
                 if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
@@ -1419,10 +1481,22 @@
                             record.mReceiver.mPackageName,
                             record.mReceiver.mAllowedResolutionLevel)) {
                         LocationRequest locationRequest = record.mRequest;
+                        long interval = locationRequest.getInterval();
+
+                        if (!isThrottlingExemptLocked(record.mReceiver)) {
+                            if (!record.mIsForegroundUid) {
+                                interval = Math.max(interval, backgroundThrottleInterval);
+                            }
+                            if (interval != locationRequest.getInterval()) {
+                                locationRequest = new LocationRequest(locationRequest);
+                                locationRequest.setInterval(interval);
+                            }
+                        }
+
                         providerRequest.locationRequests.add(locationRequest);
-                        if (locationRequest.getInterval() < providerRequest.interval) {
+                        if (interval < providerRequest.interval) {
                             providerRequest.reportLocation = true;
-                            providerRequest.interval = locationRequest.getInterval();
+                            providerRequest.interval = interval;
                         }
                     }
                 }
@@ -1468,10 +1542,15 @@
         p.setRequest(providerRequest, worksource);
     }
 
+    private boolean isThrottlingExemptLocked(Receiver recevier) {
+        return isOverlayProviderPackageLocked(recevier.mPackageName);
+    }
+
     private class UpdateRecord {
         final String mProvider;
         final LocationRequest mRequest;
         final Receiver mReceiver;
+        boolean mIsForegroundUid;
         Location mLastFixBroadcast;
         long mLastStatusBroadcast;
 
@@ -1482,10 +1561,12 @@
             mProvider = provider;
             mRequest = request;
             mReceiver = receiver;
+            mIsForegroundUid = isImportanceForeground(
+                    mActivityManager.getPackageImportance(mReceiver.mPackageName));
 
             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
             if (records == null) {
-                records = new ArrayList<UpdateRecord>();
+                records = new ArrayList<>();
                 mRecordsByProvider.put(provider, records);
             }
             if (!records.contains(this)) {
@@ -1517,7 +1598,7 @@
                 receiverRecords.remove(this.mProvider);
 
                 // and also remove the Receiver if it has no more update records
-                if (removeReceiver && receiverRecords.size() == 0) {
+                if (receiverRecords.size() == 0) {
                     removeUpdatesLocked(mReceiver);
                 }
             }
@@ -1525,14 +1606,9 @@
 
         @Override
         public String toString() {
-            StringBuilder s = new StringBuilder();
-            s.append("UpdateRecord[");
-            s.append(mProvider);
-            s.append(' ').append(mReceiver.mPackageName).append('(');
-            s.append(mReceiver.mUid).append(')');
-            s.append(' ').append(mRequest);
-            s.append(']');
-            return s.toString();
+            return "UpdateRecord[" + mProvider + " " + mReceiver.mPackageName
+                    + "(" + mReceiver.mUid + (mIsForegroundUid ? " foreground" : " background")
+                    + ")" + " " + mRequest + "]";
         }
     }
 
@@ -1681,14 +1757,17 @@
             throw new IllegalArgumentException("provider name must not be null");
         }
 
-        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
-                + " " + name + " " + request + " from " + packageName + "(" + uid + ")");
         LocationProviderInterface provider = mProvidersByName.get(name);
         if (provider == null) {
             throw new IllegalArgumentException("provider doesn't exist: " + name);
         }
 
         UpdateRecord record = new UpdateRecord(name, request, receiver);
+        if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
+                + " " + name + " " + request + " from " + packageName + "(" + uid + " "
+                + (record.mIsForegroundUid ? "foreground" : "background")
+                + (isOverlayProviderPackageLocked(receiver.mPackageName) ? " [whitelisted]" : "") + ")");
+
         UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
         if (oldRecord != null) {
             oldRecord.disposeLocked(false);
@@ -1743,7 +1822,7 @@
         receiver.updateMonitoring(false);
 
         // Record which providers were associated with this listener
-        HashSet<String> providers = new HashSet<String>();
+        HashSet<String> providers = new HashSet<>();
         HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
         if (oldRecords != null) {
             // Call dispose() on the obsolete update records.
@@ -2084,9 +2163,7 @@
         try {
             synchronized (mLock) {
                 LocationProviderInterface p = mProvidersByName.get(provider);
-                if (p == null) return false;
-
-                return isAllowedByUserSettingsLocked(provider, uid);
+                return p != null && isAllowedByUserSettingsLocked(provider, uid);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -2197,11 +2274,7 @@
         }
 
         // Check whether the expiry date has passed
-        if (record.mRequest.getExpireAt() < now) {
-            return false;
-        }
-
-        return true;
+        return record.mRequest.getExpireAt() >= now;
     }
 
     private void handleLocationChangedLocked(Location location, boolean passive) {
@@ -2216,7 +2289,7 @@
 
         // Update last known locations
         Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
-        Location lastNoGPSLocation = null;
+        Location lastNoGPSLocation;
         Location lastLocation = mLastLocation.get(provider);
         if (lastLocation == null) {
             lastLocation = new Location(provider);
@@ -2296,7 +2369,7 @@
                 continue;
             }
 
-            Location notifyLocation = null;
+            Location notifyLocation;
             if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
                 notifyLocation = coarseLocation;  // use coarse location
             } else {
@@ -2333,14 +2406,14 @@
             // track expired records
             if (r.mRequest.getNumUpdates() <= 0 || r.mRequest.getExpireAt() < now) {
                 if (deadUpdateRecords == null) {
-                    deadUpdateRecords = new ArrayList<UpdateRecord>();
+                    deadUpdateRecords = new ArrayList<>();
                 }
                 deadUpdateRecords.add(r);
             }
             // track dead receivers
             if (receiverDead) {
                 if (deadReceivers == null) {
-                    deadReceivers = new ArrayList<Receiver>();
+                    deadReceivers = new ArrayList<>();
                 }
                 if (!deadReceivers.contains(receiver)) {
                     deadReceivers.add(receiver);
@@ -2417,7 +2490,7 @@
                 for (Receiver receiver : mReceivers.values()) {
                     if (receiver.mPackageName.equals(packageName)) {
                         if (deadReceivers == null) {
-                            deadReceivers = new ArrayList<Receiver>();
+                            deadReceivers = new ArrayList<>();
                         }
                         deadReceivers.add(receiver);
                     }
@@ -2694,6 +2767,13 @@
                     pw.println("      " + record);
                 }
             }
+            pw.println("  Overlay Provider Packages:");
+            for (LocationProviderInterface provider : mProviders) {
+                if (provider instanceof LocationProviderProxy) {
+                    pw.println("    " + provider.getName() + ": "
+                            + ((LocationProviderProxy) provider).getConnectedPackageName());
+                }
+            }
             pw.println("  Historical Records by Provider:");
             for (Map.Entry<PackageProviderKey, PackageStatistics> entry
                     : mRequestStatistics.statistics.entrySet()) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 51503c0..2d40e8e 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1196,9 +1196,11 @@
         VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify,
                 hasChallenge, challenge, progressCallback);
 
-        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
-                && shouldReEnrollBaseZero) {
-            setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
+        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+            mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
+            if (shouldReEnrollBaseZero) {
+                setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
+            }
         }
 
         return response;
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
index 551ceb8..1314110 100644
--- a/services/core/java/com/android/server/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -16,23 +16,30 @@
 
 package com.android.server;
 
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.IStrongAuthTracker;
 import android.content.Context;
+import android.os.Binder;
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.SparseIntArray;
 
 import java.util.ArrayList;
 
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
-
 /**
  * Keeps track of requests for strong authentication.
  */
@@ -45,12 +52,22 @@
     private static final int MSG_UNREGISTER_TRACKER = 3;
     private static final int MSG_REMOVE_USER = 4;
 
+    private static final String STRONG_AUTH_TIMEOUT_ALARM_TAG =
+            "LockSettingsStrongAuth.timeoutForUser";
+
     private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
     private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+    private final ArrayMap<Integer, StrongAuthTimeoutAlarmListener>
+            mStrongAuthTimeoutAlarmListenerForUser = new ArrayMap<>();
     private final int mDefaultStrongAuthFlags;
+    private final Context mContext;
+
+    private AlarmManager mAlarmManager;
 
     public LockSettingsStrongAuth(Context context) {
+        mContext = context;
         mDefaultStrongAuthFlags = StrongAuthTracker.getDefaultFlags(context);
+        mAlarmManager = context.getSystemService(AlarmManager.class);
     }
 
     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
@@ -151,6 +168,46 @@
         requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
     }
 
+    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);
+        }
+    }
+
+    private class StrongAuthTimeoutAlarmListener implements OnAlarmListener {
+
+        private final int mUserId;
+
+        public StrongAuthTimeoutAlarmListener(int userId) {
+            mUserId = userId;
+        }
+
+        @Override
+        public void onAlarm() {
+            requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, mUserId);
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 74e44d5..adc5e33 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -45,6 +45,7 @@
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
+
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.ContentResolver;
@@ -374,15 +375,17 @@
         mObservers.unregister(observer);
     }
 
-    /**
-     * Notify our observers of an interface status change
-     */
-    private void notifyInterfaceStatusChanged(String iface, boolean up) {
+    @FunctionalInterface
+    private interface NetworkManagementEventCallback {
+        public void sendCallback(INetworkManagementEventObserver o) throws RemoteException;
+    }
+
+    private void invokeForAllObservers(NetworkManagementEventCallback eventCallback) {
         final int length = mObservers.beginBroadcast();
         try {
             for (int i = 0; i < length; i++) {
                 try {
-                    mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
+                    eventCallback.sendCallback(mObservers.getBroadcastItem(i));
                 } catch (RemoteException | RuntimeException e) {
                 }
             }
@@ -392,38 +395,25 @@
     }
 
     /**
+     * Notify our observers of an interface status change
+     */
+    private void notifyInterfaceStatusChanged(String iface, boolean up) {
+        invokeForAllObservers(o -> o.interfaceStatusChanged(iface, up));
+    }
+
+    /**
      * Notify our observers of an interface link state change
      * (typically, an Ethernet cable has been plugged-in or unplugged).
      */
     private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.interfaceLinkStateChanged(iface, up));
     }
 
     /**
      * Notify our observers of an interface addition.
      */
     private void notifyInterfaceAdded(String iface) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).interfaceAdded(iface);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.interfaceAdded(iface));
     }
 
     /**
@@ -435,34 +425,14 @@
         mActiveAlerts.remove(iface);
         mActiveQuotas.remove(iface);
 
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).interfaceRemoved(iface);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.interfaceRemoved(iface));
     }
 
     /**
      * Notify our observers of a limit reached.
      */
     private void notifyLimitReached(String limitName, String iface) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).limitReached(limitName, iface);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.limitReached(limitName, iface));
     }
 
     /**
@@ -509,18 +479,9 @@
             // on the mobile network, that is not coming from the radio itself, and we
             // have previously seen change reports from the radio.  In that case only
             // the radio is the authority for the current state.
-            final int length = mObservers.beginBroadcast();
-            try {
-                for (int i = 0; i < length; i++) {
-                    try {
-                        mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
-                                Integer.toString(type), isActive, tsNanos);
-                    } catch (RemoteException | RuntimeException e) {
-                    }
-                }
-            } finally {
-                mObservers.finishBroadcast();
-            }
+            final boolean active = isActive;
+            invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
+                    Integer.toString(type), active, tsNanos));
         }
 
         boolean report = false;
@@ -692,72 +653,31 @@
      * Notify our observers of a new or updated interface address.
      */
     private void notifyAddressUpdated(String iface, LinkAddress address) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).addressUpdated(iface, address);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.addressUpdated(iface, address));
     }
 
     /**
      * Notify our observers of a deleted interface address.
      */
     private void notifyAddressRemoved(String iface, LinkAddress address) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).addressRemoved(iface, address);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.addressRemoved(iface, address));
     }
 
     /**
      * Notify our observers of DNS server information received.
      */
     private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
-                        addresses);
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
-        }
+        invokeForAllObservers(o -> o.interfaceDnsServerInfo(iface, lifetime, addresses));
     }
 
     /**
      * Notify our observers of a route change.
      */
     private void notifyRouteChange(String action, RouteInfo route) {
-        final int length = mObservers.beginBroadcast();
-        try {
-            for (int i = 0; i < length; i++) {
-                try {
-                    if (action.equals("updated")) {
-                        mObservers.getBroadcastItem(i).routeUpdated(route);
-                    } else {
-                        mObservers.getBroadcastItem(i).routeRemoved(route);
-                    }
-                } catch (RemoteException | RuntimeException e) {
-                }
-            }
-        } finally {
-            mObservers.finishBroadcast();
+        if (action.equals("updated")) {
+            invokeForAllObservers(o -> o.routeUpdated(route));
+        } else {
+            invokeForAllObservers(o -> o.routeRemoved(route));
         }
     }
 
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index bd9f684..e8ecc3e 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -75,6 +75,7 @@
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 
 /**
@@ -87,7 +88,7 @@
 
     private final Context mContext;
     private final NetworkScorerAppManager mNetworkScorerAppManager;
-    private final RequestRecommendationCaller mRequestRecommendationCaller;
+    private final AtomicReference<RequestRecommendationCaller> mReqRecommendationCallerRef;
     @GuardedBy("mScoreCaches")
     private final Map<Integer, RemoteCallbackList<INetworkScoreCache>> mScoreCaches;
     /** Lock used to update mPackageMonitor when scorer package changes occur. */
@@ -249,8 +250,8 @@
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.SYSTEM, filter, null /* broadcastPermission*/,
                 null /* scheduler */);
-        mRequestRecommendationCaller =
-            new RequestRecommendationCaller(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+        mReqRecommendationCallerRef = new AtomicReference<>(
+                new RequestRecommendationCaller(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS));
         mRecommendationRequestTimeoutMs = TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS;
         mHandler = new ServiceHandler(looper);
         mContentObserver = new DispatchingContentObserver(context, mHandler);
@@ -569,7 +570,8 @@
             final INetworkRecommendationProvider provider = getRecommendationProvider();
             if (provider != null) {
                 try {
-                    return mRequestRecommendationCaller.getRecommendationResult(provider, request);
+                    final RequestRecommendationCaller caller = mReqRecommendationCallerRef.get();
+                    return caller.getRecommendationResult(provider, request);
                 } catch (RemoteException | TimeoutException e) {
                     Log.w(TAG, "Failed to request a recommendation.", e);
                     // TODO(jjoslin): 12/15/16 - Keep track of failures.
@@ -580,9 +582,9 @@
                 Log.d(TAG, "Returning the default network recommendation.");
             }
 
-            if (request != null && request.getCurrentSelectedConfig() != null) {
+            if (request != null && request.getDefaultWifiConfig() != null) {
                 return RecommendationResult.createConnectRecommendation(
-                        request.getCurrentSelectedConfig());
+                        request.getDefaultWifiConfig());
             }
             return RecommendationResult.createDoNotConnectRecommendation();
         } finally {
@@ -602,7 +604,7 @@
     @Override
     public void requestRecommendationAsync(RecommendationRequest request,
             RemoteCallback remoteCallback) {
-        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+        mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
 
         final OneTimeCallback oneTimeCallback = new OneTimeCallback(remoteCallback);
         final Pair<RecommendationRequest, OneTimeCallback> pair =
@@ -748,6 +750,7 @@
         }
         if (DBG) Log.d(TAG, "Updating the recommendation request timeout to " + timeoutMs + " ms");
         mRecommendationRequestTimeoutMs = timeoutMs;
+        mReqRecommendationCallerRef.set(new RequestRecommendationCaller(timeoutMs));
     }
 
     private static class ScoringServiceConnection implements ServiceConnection {
@@ -884,9 +887,9 @@
         }
 
         final RecommendationResult result;
-        if (request != null && request.getCurrentSelectedConfig() != null) {
+        if (request != null && request.getDefaultWifiConfig() != null) {
             result = RecommendationResult.createConnectRecommendation(
-                    request.getCurrentSelectedConfig());
+                    request.getDefaultWifiConfig());
         } else {
             result = RecommendationResult.createDoNotConnectRecommendation();
         }
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index 2010e64..3c8c699 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -181,7 +181,7 @@
         }
 
         @Override // Binder call
-        public void rebootRecoveryWithCommand(String command, boolean update) {
+        public void rebootRecoveryWithCommand(String command) {
             if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
             synchronized (sRequestLock) {
                 if (!setupOrClearBcb(true, command)) {
@@ -190,10 +190,7 @@
 
                 // Having set up the BCB, go ahead and reboot.
                 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-                // PowerManagerService may additionally request uncrypting the package when it's
-                // to install an update (REBOOT_RECOVERY_UPDATE).
-                pm.reboot(update ? PowerManager.REBOOT_RECOVERY_UPDATE :
-                        PowerManager.REBOOT_RECOVERY);
+                pm.reboot(PowerManager.REBOOT_RECOVERY);
             }
         }
 
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
new file mode 100644
index 0000000..bb8401f
--- /dev/null
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -0,0 +1,299 @@
+/*
+ * 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;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.RecoverySystem;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.ExceptionUtils;
+import android.util.MathUtils;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Utilities to help rescue the system from crash loops. Callers are expected to
+ * report boot events and persistent app crashes, and if they happen frequently
+ * enough this class will slowly escalate through several rescue operations
+ * before finally rebooting and prompting the user if they want to wipe data as
+ * a last resort.
+ *
+ * @hide
+ */
+public class RescueParty {
+    private static final String TAG = "RescueParty";
+
+    private static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
+    private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
+    private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
+
+    private static final int LEVEL_NONE = 0;
+    private static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
+    private static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
+    private static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
+    private static final int LEVEL_FACTORY_RESET = 4;
+
+    /** Threshold for boot loops */
+    private static final Threshold sBoot = new BootThreshold();
+    /** Threshold for app crash loops */
+    private static SparseArray<Threshold> sApps = new SparseArray<>();
+
+    /**
+     * Take note of a boot event. If we notice too many of these events
+     * happening in rapid succession, we'll send out a rescue party.
+     */
+    public static void noteBoot(Context context) {
+        if (sBoot.incrementAndTest()) {
+            sBoot.reset();
+            incrementRescueLevel(sBoot.uid);
+            executeRescueLevel(context);
+        }
+    }
+
+    /**
+     * Take note of a persistent app crash. If we notice too many of these
+     * events happening in rapid succession, we'll send out a rescue party.
+     */
+    public static void notePersistentAppCrash(Context context, int uid) {
+        Threshold t = sApps.get(uid);
+        if (t == null) {
+            t = new AppThreshold(uid);
+            sApps.put(uid, t);
+        }
+        if (t.incrementAndTest()) {
+            t.reset();
+            incrementRescueLevel(t.uid);
+            executeRescueLevel(context);
+        }
+    }
+
+    /**
+     * Check if we're currently attempting to reboot for a factory reset.
+     */
+    public static boolean isAttemptingFactoryReset() {
+        return SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) == LEVEL_FACTORY_RESET;
+    }
+
+    /**
+     * Escalate to the next rescue level. After incrementing the level you'll
+     * probably want to call {@link #executeRescueLevel(Context)}.
+     */
+    private static void incrementRescueLevel(int triggerUid) {
+        final int level = MathUtils.constrain(
+                SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
+                LEVEL_NONE, LEVEL_FACTORY_RESET);
+        SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
+
+        EventLogTags.writeRescueLevel(level, triggerUid);
+        Slog.w(TAG, "Incremented rescue level to " + levelToString(level));
+    }
+
+    /**
+     * Called when {@code SettingsProvider} has been published, which is a good
+     * opportunity to reset any settings depending on our rescue level.
+     */
+    public static void onSettingsProviderPublished(Context context) {
+        executeRescueLevel(context);
+    }
+
+    private static void executeRescueLevel(Context context) {
+        final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
+        if (level == LEVEL_NONE) return;
+
+        Slog.w(TAG, "Attempting rescue level " + levelToString(level));
+        try {
+            executeRescueLevelInternal(context, level);
+            EventLogTags.writeRescueSuccess(level);
+            Slog.d(TAG, "Finished rescue level " + levelToString(level));
+        } catch (Throwable t) {
+            EventLogTags.writeRescueFailure(level, ExceptionUtils.getCompleteMessage(t));
+            Slog.e(TAG, "Failed rescue level " + levelToString(level), t);
+        }
+    }
+
+    private static void executeRescueLevelInternal(Context context, int level) throws Exception {
+        switch (level) {
+            case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
+                resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+                break;
+            case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
+                resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES);
+                break;
+            case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
+                resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+                break;
+            case LEVEL_FACTORY_RESET:
+                RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
+                break;
+        }
+    }
+
+    private static void resetAllSettings(Context context, int mode) throws Exception {
+        // Try our best to reset all settings possible, and once finished
+        // rethrow any exception that we encountered
+        Exception res = null;
+        final ContentResolver resolver = context.getContentResolver();
+        try {
+            Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
+        } catch (Exception e) {
+            res = new RuntimeException("Failed to reset global settings", e);
+        }
+        for (int userId : getAllUserIds(context)) {
+            try {
+                Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
+            } catch (Exception e) {
+                res = new RuntimeException("Failed to reset secure settings for " + userId, e);
+            }
+        }
+        if (res != null) {
+            throw res;
+        }
+    }
+
+    /**
+     * Threshold that can be triggered if a number of events occur within a
+     * window of time.
+     */
+    private abstract static class Threshold {
+        public abstract int getCount();
+        public abstract void setCount(int count);
+        public abstract long getStart();
+        public abstract void setStart(long start);
+
+        private final int uid;
+        private final int triggerCount;
+        private final long triggerWindow;
+
+        public Threshold(int uid, int triggerCount, long triggerWindow) {
+            this.uid = uid;
+            this.triggerCount = triggerCount;
+            this.triggerWindow = triggerWindow;
+        }
+
+        public void reset() {
+            setCount(0);
+            setStart(0);
+        }
+
+        /**
+         * @return if this threshold has been triggered
+         */
+        public boolean incrementAndTest() {
+            final long now = SystemClock.elapsedRealtime();
+            final long window = now - getStart();
+            if (window > triggerWindow) {
+                setCount(1);
+                setStart(now);
+                return false;
+            } else {
+                int count = getCount() + 1;
+                setCount(count);
+                EventLogTags.writeRescueNote(uid, count, window);
+                Slog.w(TAG, "Noticed " + count + " events for UID " + uid + " in last "
+                        + (window / 1000) + " sec");
+                return (count >= triggerCount);
+            }
+        }
+    }
+
+    /**
+     * Specialization of {@link Threshold} for monitoring boot events. It stores
+     * counters in system properties for robustness.
+     */
+    private static class BootThreshold extends Threshold {
+        public BootThreshold() {
+            // We're interested in 5 events in any 300 second period; this
+            // window is super relaxed because booting can take a long time if
+            // forced to dexopt things.
+            super(android.os.Process.ROOT_UID, 5, 300 * DateUtils.SECOND_IN_MILLIS);
+        }
+
+        @Override
+        public int getCount() {
+            return SystemProperties.getInt(PROP_RESCUE_BOOT_COUNT, 0);
+        }
+
+        @Override
+        public void setCount(int count) {
+            SystemProperties.set(PROP_RESCUE_BOOT_COUNT, Integer.toString(count));
+        }
+
+        @Override
+        public long getStart() {
+            return SystemProperties.getLong(PROP_RESCUE_BOOT_START, 0);
+        }
+
+        @Override
+        public void setStart(long start) {
+            SystemProperties.set(PROP_RESCUE_BOOT_START, Long.toString(start));
+        }
+    }
+
+    /**
+     * Specialization of {@link Threshold} for monitoring app crashes. It stores
+     * counters in memory.
+     */
+    private static class AppThreshold extends Threshold {
+        private int count;
+        private long start;
+
+        public AppThreshold(int uid) {
+            // We're interested in 5 events in any 30 second period; apps crash
+            // pretty quickly so we can keep a tight leash on them.
+            super(uid, 5, 30 * DateUtils.SECOND_IN_MILLIS);
+        }
+
+        @Override public int getCount() { return count; }
+        @Override public void setCount(int count) { this.count = count; }
+        @Override public long getStart() { return start; }
+        @Override public void setStart(long start) { this.start = start; }
+    }
+
+    private static int[] getAllUserIds(Context context) {
+        int[] userIds = { UserHandle.USER_SYSTEM };
+        try {
+            final UserManager um = context.getSystemService(UserManager.class);
+            for (UserInfo user : um.getUsers()) {
+                if (user.id != UserHandle.USER_SYSTEM) {
+                    userIds = ArrayUtils.appendInt(userIds, user.id);
+                }
+            }
+        } catch (Throwable t) {
+            Slog.w(TAG, "Trouble discovering users", t);
+        }
+        return userIds;
+    }
+
+    private static String levelToString(int level) {
+        switch (level) {
+            case LEVEL_NONE: return "NONE";
+            case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS";
+            case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES";
+            case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS";
+            case LEVEL_FACTORY_RESET: return "FACTORY_RESET";
+            default: return Integer.toString(level);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 55d31c3..e11dd1a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -33,6 +33,7 @@
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
+import android.app.usage.StorageStatsManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -88,11 +89,13 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
+import com.android.internal.os.AppFuseMount;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
@@ -104,7 +107,7 @@
 import com.android.server.NativeDaemonConnector.Command;
 import com.android.server.NativeDaemonConnector.SensitiveArg;
 import com.android.server.pm.PackageManagerService;
-
+import com.android.server.storage.AppFuseBridge;
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
@@ -135,6 +138,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -337,6 +341,15 @@
 
     private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
 
+    /** Holding lock for AppFuse business */
+    private final Object mAppFuseLock = new Object();
+
+    @GuardedBy("mAppFuseLock")
+    private int mNextAppFuseName = 0;
+
+    @GuardedBy("mAppFuseLock")
+    private final SparseArray<Integer> mAppFusePids = new SparseArray<>();
+
     private VolumeInfo findVolumeByIdOrThrow(String id) {
         synchronized (mLock) {
             final VolumeInfo vol = mVolumes.get(id);
@@ -2979,34 +2992,124 @@
         }
     }
 
-    @Override
-    public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
-        try {
-            final int uid = Binder.getCallingUid();
-            final int pid = Binder.getCallingPid();
-            final NativeDaemonEvent event =
-                    mConnector.execute("appfuse", "mount", uid, pid, name);
-            if (event.getFileDescriptors() == null) {
-                throw new RemoteException("AppFuse FD from vold is null.");
+    class CloseableHolder<T extends AutoCloseable> implements AutoCloseable {
+        @Nullable T mCloseable;
+
+        CloseableHolder(T closeable) {
+            mCloseable = closeable;
+        }
+
+        @Nullable T get() {
+            return mCloseable;
+        }
+
+        @Nullable T release() {
+            final T result = mCloseable;
+            mCloseable = null;
+            return result;
+        }
+
+        @Override
+        public void close() {
+            if (mCloseable != null) {
+                IoUtils.closeQuietly(mCloseable);
             }
-            return ParcelFileDescriptor.fromFd(
-                    event.getFileDescriptors()[0],
-                    mHandler,
-                    new ParcelFileDescriptor.OnCloseListener() {
-                        @Override
-                        public void onClose(IOException e) {
-                            try {
-                                final NativeDaemonEvent event = mConnector.execute(
-                                        "appfuse", "unmount", uid, pid, name);
-                            } catch (NativeDaemonConnectorException unmountException) {
-                                Log.e(TAG, "Failed to unmount appfuse.");
-                            }
-                        }
-                    });
-        } catch (NativeDaemonConnectorException e) {
+        }
+    }
+
+    class AppFuseMountScope implements AppFuseBridge.IMountScope {
+        final int mUid;
+        final int mName;
+        final ParcelFileDescriptor mDeviceFd;
+
+        AppFuseMountScope(int uid, int pid, int name) throws NativeDaemonConnectorException {
+            final NativeDaemonEvent event = mConnector.execute(
+                    "appfuse", "mount", uid, Process.myPid(), name);
+            mUid = uid;
+            mName = name;
+            synchronized (mLock) {
+                mAppFusePids.put(name, pid);
+            }
+            if (event.getFileDescriptors() != null &&
+                    event.getFileDescriptors().length > 0) {
+                mDeviceFd = new ParcelFileDescriptor(event.getFileDescriptors()[0]);
+            } else {
+                mDeviceFd = null;
+            }
+        }
+
+        @Override
+        public void close() throws NativeDaemonConnectorException {
+            try {
+                IoUtils.closeQuietly(mDeviceFd);
+                mConnector.execute(
+                        "appfuse", "unmount", mUid, Process.myPid(), mName);
+            } finally {
+                synchronized (mLock) {
+                    mAppFusePids.delete(mName);
+                }
+            }
+        }
+
+        @Override
+        public ParcelFileDescriptor getDeviceFileDescriptor() {
+            return mDeviceFd;
+        }
+    }
+
+    @Override
+    public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        final int name;
+        synchronized (mAppFuseLock) {
+            name = mNextAppFuseName++;
+        }
+        try (CloseableHolder<AppFuseMountScope> mountScope =
+                new CloseableHolder<>(new AppFuseMountScope(uid, pid, name))) {
+            if (mountScope.get().getDeviceFileDescriptor() == null) {
+                throw new RemoteException("Failed to obtain device FD");
+            }
+
+            // Create communication channel.
+            final ArrayBlockingQueue<Boolean> channel = new ArrayBlockingQueue<>(1);
+            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair();
+            try (CloseableHolder<ParcelFileDescriptor> remote = new CloseableHolder<>(fds[0])) {
+                new Thread(
+                        new AppFuseBridge(mountScope.release(), fds[1], channel),
+                        AppFuseBridge.TAG).start();
+                if (!channel.take()) {
+                    throw new RemoteException("Failed to init AppFuse mount point");
+                }
+
+                return new AppFuseMount(name, remote.release());
+            }
+        } catch (NativeDaemonConnectorException e){
             throw e.rethrowAsParcelableException();
-        } catch (IOException e) {
-            throw new RemoteException(e.getMessage());
+        } catch (IOException | InterruptedException error) {
+            throw new RemoteException(error.getMessage());
+        }
+    }
+
+    @Override
+    public ParcelFileDescriptor openProxyFileDescriptor(int mountId, int fileId, int mode) {
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        try {
+            synchronized (mAppFuseLock) {
+                final int expectedPid = mAppFusePids.get(mountId, -1);
+                if (expectedPid == -1) {
+                    Slog.i(TAG, "The mount point has already been unmounted");
+                    return null;
+                }
+                if (expectedPid != pid) {
+                    throw new SecurityException("Mount point was not created by this process.");
+                }
+            }
+            return AppFuseBridge.openFile(uid, mountId, fileId, mode);
+        } catch (FileNotFoundException error) {
+            Slog.e(TAG, "Failed to openProxyFileDescriptor", error);
+            return null;
         }
     }
 
@@ -3168,6 +3271,29 @@
         }
     }
 
+    @Override
+    public long getCacheQuotaBytes(String volumeUuid, int uid) {
+        if (uid != Binder.getCallingUid()) {
+            mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
+        }
+        // TODO: wire up to cache quota once merged
+        return 64 * TrafficStats.MB_IN_BYTES;
+    }
+
+    @Override
+    public long getCacheSizeBytes(String volumeUuid, int uid) {
+        if (uid != Binder.getCallingUid()) {
+            mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
+        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return mContext.getSystemService(StorageStatsManager.class)
+                    .queryStatsForUid(volumeUuid, uid).getCacheBytes();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private void addObbStateLocked(ObbState obbState) throws RemoteException {
         final IBinder binder = obbState.getBinder();
         List<ObbState> obbStates = mObbMounts.get(binder);
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index d879919..3f97d4f 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -36,7 +36,6 @@
     private final Context mContext;
     private boolean mSafeMode;
     private boolean mRuntimeRestarted;
-    private boolean mFirstBoot;
 
     // Services that should receive lifecycle events.
     private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
@@ -260,16 +259,6 @@
         mRuntimeRestarted = runtimeRestarted;
     }
 
-    /**
-     * @return true if it's first boot after OTA
-     */
-    public boolean isFirstBoot() {
-        return mFirstBoot;
-    }
-
-    void setFirstBoot(boolean firstBoot) {
-        mFirstBoot = firstBoot;
-    }
 
     /**
      * Outputs the state of this manager to the System log.
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62f4f19..0834eb8 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1360,6 +1360,7 @@
         }
 
         Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         Bundle data = new Bundle();
         state.fillInNotifierBundle(data);
         intent.putExtras(data);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 11e1a9d..0a6c62f 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -505,7 +505,9 @@
      * @param ua UserAccount that currently hosts the account and application
      */
     private void registerAccountTypesSupported(int uid, UserAccounts ua) {
-        /* Account types supported are drawn from the Android Manifest of the Application */
+        return;
+        // TODO clean up the code, manifest entry is deprecated
+        /*
         String interestedPackages = null;
         try {
             String[] allPackages = mPackageManager.getPackagesForUid(uid);
@@ -527,6 +529,7 @@
             // TODO request visibility
             // requestAccountVisibility(interestedPackages.split(";"), uid, ua);
         }
+        */
     }
 
     /**
@@ -536,6 +539,8 @@
      * @param visibleAccount to send to package
      */
     private void sendNotification(String desiredPackage, Account visibleAccount) {
+        // TODO replace with callback
+        /*
         Intent intent = new Intent();
         intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
         intent.setAction(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
@@ -543,6 +548,7 @@
         // TODO update documentation, add account extra if new account became visible
         // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
         mContext.sendBroadcast(intent);
+        */
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7661127..5655dc5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -305,6 +305,7 @@
     }
 
     ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
+            int id, Notification notification,
             int callingPid, int callingUid, String callingPackage, final int userId)
             throws TransactionTooLargeException {
         if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
@@ -324,7 +325,6 @@
             callerFg = true;
         }
 
-
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType, callingPackage,
                     callingPid, callingUid, userId, true, callerFg, false);
@@ -343,19 +343,27 @@
             return null;
         }
 
-        if (!r.startRequested) {
+        // Non-null notification means this is a start directly into the foreground
+        if (!r.startRequested && notification == null) {
             final long token = Binder.clearCallingIdentity();
             try {
-                // Before going further -- if this app is not allowed to run in the
+                // Before going further -- if this app is not allowed to start services in the
                 // background, then at this point we aren't going to let it period.
-                final int allowed = mAm.checkAllowBackgroundLocked(
-                        r.appInfo.uid, r.packageName, callingPid, false);
+                final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
+                        r.appInfo.targetSdkVersion, callingPid, false, false);
                 if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                     Slog.w(TAG, "Background start not allowed: service "
                             + service + " to " + r.name.flattenToShortString()
                             + " from pid=" + callingPid + " uid=" + callingUid
                             + " pkg=" + callingPackage);
-                    return null;
+                    if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
+                        // In this case we are silently disabling the app, to disrupt as
+                        // little as possible existing apps.
+                        return null;
+                    }
+                    // This app knows it is in the new model where this operation is not
+                    // allowed, so tell it what has happened.
+                    return new ComponentName("?", "app is in background");
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -450,7 +458,11 @@
             }
         }
 
-        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
+        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
+        if (notification != null) {
+            setServiceForegroundInnerLocked(r, callingUid, notification, 0);
+        }
+        return cmp;
     }
 
     private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
@@ -595,9 +607,9 @@
             for (int i=services.mServicesByName.size()-1; i>=0; i--) {
                 ServiceRecord service = services.mServicesByName.valueAt(i);
                 if (service.appInfo.uid == uid && service.startRequested) {
-                    if (service.appInfo.isEphemeralApp() ||
-                            mAm.mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
-                            uid, service.packageName) != AppOpsManager.MODE_ALLOWED) {
+                    if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName,
+                            service.appInfo.targetSdkVersion, -1, false, false)
+                            != ActivityManager.APP_START_MODE_NORMAL) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
                             stopping.add(service);
@@ -696,50 +708,55 @@
         try {
             ServiceRecord r = findServiceLocked(className, token, userId);
             if (r != null) {
-                if (id != 0) {
-                    if (notification == null) {
-                        throw new IllegalArgumentException("null notification");
-                    }
-                    if (r.foregroundId != id) {
-                        cancelForegroudNotificationLocked(r);
-                        r.foregroundId = id;
-                    }
-                    notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
-                    r.foregroundNoti = notification;
-                    r.isForeground = true;
-                    r.postNotification();
-                    if (r.app != null) {
-                        updateServiceForegroundLocked(r.app, true);
-                    }
-                    getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
-                    mAm.notifyPackageUse(r.serviceInfo.packageName,
-                                         PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
-                } else {
-                    if (r.isForeground) {
-                        r.isForeground = false;
-                        if (r.app != null) {
-                            mAm.updateLruProcessLocked(r.app, false, null);
-                            updateServiceForegroundLocked(r.app, true);
-                        }
-                    }
-                    if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
-                        cancelForegroudNotificationLocked(r);
-                        r.foregroundId = 0;
-                        r.foregroundNoti = null;
-                    } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
-                        r.stripForegroundServiceFlagFromNotification();
-                        if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
-                            r.foregroundId = 0;
-                            r.foregroundNoti = null;
-                        }
-                    }
-                }
+                setServiceForegroundInnerLocked(r, id, notification, flags);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
+            Notification notification, int flags) {
+        if (id != 0) {
+            if (notification == null) {
+                throw new IllegalArgumentException("null notification");
+            }
+            if (r.foregroundId != id) {
+                cancelForegroudNotificationLocked(r);
+                r.foregroundId = id;
+            }
+            notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+            r.foregroundNoti = notification;
+            r.isForeground = true;
+            r.postNotification();
+            if (r.app != null) {
+                updateServiceForegroundLocked(r.app, true);
+            }
+            getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
+            mAm.notifyPackageUse(r.serviceInfo.packageName,
+                                 PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
+        } else {
+            if (r.isForeground) {
+                r.isForeground = false;
+                if (r.app != null) {
+                    mAm.updateLruProcessLocked(r.app, false, null);
+                    updateServiceForegroundLocked(r.app, true);
+                }
+            }
+            if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
+                cancelForegroudNotificationLocked(r);
+                r.foregroundId = 0;
+                r.foregroundNoti = null;
+            } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
+                r.stripForegroundServiceFlagFromNotification();
+                if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
+                    r.foregroundId = 0;
+                    r.foregroundNoti = null;
+                }
+            }
+        }
+    }
+
     private void cancelForegroudNotificationLocked(ServiceRecord r) {
         if (r.foregroundId != 0) {
             // First check to see if this app has any other active foreground services
@@ -1444,6 +1461,8 @@
             // If service is not currently running, can't yet bind.
             return false;
         }
+        if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+                + " rebind=" + rebind);
         if ((!i.requested || rebind) && i.apps.size() > 0) {
             try {
                 bumpServiceExecutingLocked(r, execInFg, "bind");
@@ -1907,6 +1926,7 @@
                     mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                             si.getUriPermissionsLocked());
                 }
+                // TODO b/34123112; Insert ephemeral grant here
                 bumpServiceExecutingLocked(r, execInFg, "start");
                 if (!oomAdjusted) {
                     oomAdjusted = true;
@@ -2014,6 +2034,7 @@
                         bumpServiceExecutingLocked(r, false, "bring down unbind");
                         mAm.updateOomAdjLocked(r.app);
                         ibr.hasBound = false;
+                        ibr.requested = false;
                         r.app.thread.scheduleUnbindService(r,
                                 ibr.intent.getIntent());
                     } catch (Exception e) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 43bb5ee..88e0d03 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -48,6 +48,7 @@
     static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_ANR = false;
     static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
+    static final boolean DEBUG_BACKGROUND_CHECK = DEBUG_ALL || false;
     static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
     static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
     static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7fd91cb..a72950b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,6 +22,7 @@
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -62,6 +63,7 @@
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
@@ -119,6 +121,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
 import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
@@ -151,7 +154,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManager.TaskThumbnailInfo;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityManagerInternal.PictureInPictureArguments;
 import android.app.ActivityManagerInternal.SleepToken;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -182,6 +184,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.PictureInPictureArgs;
 import android.app.ProfilerInfo;
 import android.app.RemoteAction;
 import android.app.WaitResult;
@@ -229,7 +232,6 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.location.LocationManager;
@@ -310,7 +312,6 @@
 
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
-
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.AssistUtils;
@@ -340,7 +341,9 @@
 import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
+import com.android.server.RescueParty;
 import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.Watchdog;
@@ -384,10 +387,10 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dalvik.system.VMRuntime;
+
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
-import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
@@ -758,6 +761,23 @@
     ProcessRecord mHeavyWeightProcess = null;
 
     /**
+     * Are we enforcing background restrictions?
+     */
+    final boolean mEnforceBackgroundCheck;
+
+    /**
+     * Non-persistent app uid whitelist for background restrictions
+     */
+    int[] mBackgroundUidWhitelist = new int[] {
+            Process.BLUETOOTH_UID
+    };
+
+    /**
+     * Broadcast actions that will always be deliverable to unlaunched/background apps
+     */
+    final ArraySet<String> mBackgroundLaunchBroadcasts;
+
+    /**
      * All of the processes we currently have running organized by pid.
      * The keys are the pid running the application.
      *
@@ -1135,6 +1155,16 @@
     DeviceIdleController.LocalService mLocalDeviceIdleController;
 
     /**
+     * Set of app ids that are whitelisted for device idle and thus background check.
+     */
+    int[] mDeviceIdleWhitelist = new int[0];
+
+    /**
+     * Set of app ids that are temporarily allowed to escape bg check due to high-pri message
+     */
+    int[] mDeviceIdleTempWhitelist = new int[0];
+
+    /**
      * Information about and control over application operations
      */
     final AppOpsService mAppOpsService;
@@ -2590,6 +2620,19 @@
         mPermissionReviewRequired = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
+        mEnforceBackgroundCheck = SystemProperties.getBoolean("debug.bgcheck", false);
+        mBackgroundLaunchBroadcasts = SystemConfig.getInstance().getAllowImplicitBroadcasts();
+        if (DEBUG_BACKGROUND_CHECK) {
+            Slog.d(TAG, "Enforcing O+ bg restrictions: " + mEnforceBackgroundCheck);
+            StringBuilder sb = new StringBuilder(200);
+            sb.append("  ");
+            for (String a : mBackgroundLaunchBroadcasts) {
+                sb.append(' '); sb.append(a);
+            }
+            Slog.d(TAG, "Background implicit broadcasts:");
+            Slog.d(TAG, sb.toString());
+        }
+
         mHandlerThread = new ServiceThread(TAG,
                 android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
         mHandlerThread.start();
@@ -4190,7 +4233,7 @@
                             validateUid = mValidateUids.get(item.uid);
                             if (validateUid == null && change != UidRecord.CHANGE_GONE
                                     && change != UidRecord.CHANGE_GONE_IDLE) {
-                                validateUid = new UidRecord(item.uid);
+                                validateUid = new UidRecord(item.uid, false);
                                 mValidateUids.put(item.uid, validateUid);
                             }
                         }
@@ -4894,7 +4937,7 @@
     }
 
     @Override
-    public void crashApplication(int uid, int initialPid, String packageName,
+    public void crashApplication(int uid, int initialPid, String packageName, int userId,
             String message) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -4907,7 +4950,7 @@
         }
 
         synchronized(this) {
-            mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, message);
+            mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message);
         }
     }
 
@@ -5504,6 +5547,7 @@
 
                     final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
                             Uri.fromParts("package", packageName, null));
+                    intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                     intent.putExtra(Intent.EXTRA_UID, pkgUidF);
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUidF));
                     broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
@@ -5524,11 +5568,9 @@
                     removeUriPermissionsForPackageLocked(packageName, userId, true);
                 }
 
-                // Remove all zen rules created by this package; revoke it's zen access.
+                // Reset notification settings.
                 INotificationManager inm = NotificationManager.getService();
-                inm.removeAutomaticZenRules(packageName);
-                inm.setNotificationPolicyAccessGranted(packageName, false);
-
+                inm.clearData(packageName, pkgUidF);
             } catch (RemoteException e) {
             }
         } finally {
@@ -6279,10 +6321,13 @@
         }
         UidRecord uidRec = mActiveUids.get(proc.uid);
         if (uidRec == null) {
-            uidRec = new UidRecord(proc.uid);
+            uidRec = new UidRecord(proc.uid, proc.persistent);
             // This is the first appearance of the uid, report it now!
             if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                     "Creating new process uid: " + uidRec);
+            if (Arrays.binarySearch(mDeviceIdleTempWhitelist, UserHandle.getAppId(proc.uid)) >= 0) {
+                uidRec.setWhitelist = uidRec.curWhitelist = true;
+            }
             mActiveUids.put(proc.uid, uidRec);
             noteUidProcessState(uidRec.uid, uidRec.curProcState);
             enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
@@ -7240,18 +7285,23 @@
             Slog.d(TAG, "tempWhitelistAppForPowerSave(" + callerPid + ", " + callerUid + ", "
                     + targetUid + ", " + duration + ")");
         }
-        synchronized (mPidsSelfLocked) {
-            final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
-            if (pr == null) {
-                Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " + callerPid);
-                return;
-            }
-            if (!pr.whitelistManager) {
-                if (DEBUG_WHITELISTS) {
-                    Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid + ": pid "
-                            + callerPid + " is not allowed");
+
+        if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid)
+                != PackageManager.PERMISSION_GRANTED) {
+            synchronized (mPidsSelfLocked) {
+                final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
+                if (pr == null) {
+                    Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid "
+                            + callerPid);
+                    return;
                 }
-                return;
+                if (!pr.whitelistManager) {
+                    if (DEBUG_WHITELISTS) {
+                        Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid
+                                + ": pid " + callerPid + " is not allowed");
+                    }
+                    return;
+                }
             }
         }
 
@@ -7556,45 +7606,31 @@
     }
 
     @Override
-    public void enterPictureInPictureMode(IBinder token) {
-        enterPictureInPictureMode(token, DEFAULT_DISPLAY, -1f /* aspectRatio */,
-                false /* checkAspectRatio */);
-    }
-
-    @Override
-    public void enterPictureInPictureModeWithAspectRatio(IBinder token, float aspectRatio) {
-        enterPictureInPictureMode(token, DEFAULT_DISPLAY, aspectRatio, true /* checkAspectRatio */);
-    }
-
-    @Override
-    public void enterPictureInPictureModeOnMoveToBackground(IBinder token,
-            boolean enterPictureInPictureOnMoveToBg) {
+    public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureArgs args) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "enterPictureInPictureModeOnMoveToBackground", token, -1f /* aspectRatio */,
-                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
+                final ActivityRecord r = ensureValidPictureInPictureActivityArgsLocked(
+                        "enterPictureInPictureMode", token, args);
 
-                r.supportsPipOnMoveToBackground = enterPictureInPictureOnMoveToBg;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
+                // Activity supports picture-in-picture, now check that we can enter PiP at this
+                // point, if it is
+                if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode")) {
+                    return false;
+                }
 
-    private void enterPictureInPictureMode(IBinder token, int displayId, float aspectRatio,
-            boolean checkAspectRatio) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "enterPictureInPictureMode", token, aspectRatio, checkAspectRatio,
-                        true /* checkActivityVisibility */);
                 final Runnable enterPipRunnable = () -> {
-                    r.pictureInPictureArgs.aspectRatio = aspectRatio;
-                    enterPictureInPictureModeLocked(r, displayId, r.pictureInPictureArgs,
-                            true /* moveHomeStackToFront */, "enterPictureInPictureMode");
+                    // Only update the saved args from the args that are set
+                    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);
+                    mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
+                            bounds, true /* moveHomeStackToFront */);
+                    mWindowManager.setPictureInPictureActions(actions);
                 };
 
                 if (isKeyguardLocked()) {
@@ -7625,35 +7661,7 @@
                     // Enter picture in picture immediately otherwise
                     enterPipRunnable.run();
                 }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    void enterPictureInPictureModeLocked(ActivityRecord r, int displayId,
-            PictureInPictureArguments pipArgs, boolean moveHomeStackToFront, String reason) {
-        final Rect bounds = isValidPictureInPictureAspectRatio(pipArgs.aspectRatio)
-                ? mWindowManager.getPictureInPictureBounds(displayId, pipArgs.aspectRatio)
-                : mWindowManager.getPictureInPictureDefaultBounds(displayId);
-        mStackSupervisor.moveActivityToPinnedStackLocked(r, reason, bounds, moveHomeStackToFront);
-        mWindowManager.setPictureInPictureActions(pipArgs.userActions);
-    }
-
-    @Override
-    public void setPictureInPictureAspectRatio(IBinder token, float aspectRatio) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "setPictureInPictureAspectRatio", token, aspectRatio,
-                        true /* checkAspectRatio */, false /* checkActivityVisibility */);
-
-                r.pictureInPictureArgs.aspectRatio = aspectRatio;
-                if (r.getStack().getStackId() == PINNED_STACK_ID) {
-                    // If the activity is already in picture-in-picture, update the pinned stack now
-                    mWindowManager.setPictureInPictureAspectRatio(aspectRatio);
-                }
+                return true;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -7661,26 +7669,21 @@
     }
 
     @Override
-    public void setPictureInPictureActions(IBinder token, ParceledListSlice actionsList) {
+    public void setPictureInPictureArgs(IBinder token, final PictureInPictureArgs args) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized(this) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityLocked(
-                        "setPictureInPictureActions", token, -1 /* aspectRatio */,
-                        false /* checkAspectRatio */, false /* checkActivityVisibility */);
+                final ActivityRecord r = ensureValidPictureInPictureActivityArgsLocked(
+                        "setPictureInPictureArgs", token, args);
 
-                final List<RemoteAction> actions = actionsList.getList();
-                if (actions.size() > ActivityManager.getMaxNumPictureInPictureActions()) {
-                    throw new IllegalArgumentException("setPictureInPictureActions: Invalid number"
-                            + " of picture-in-picture actions.  Only a maximum of "
-                            + ActivityManager.getMaxNumPictureInPictureActions()
-                            + " actions allowed");
-                }
-
-                r.pictureInPictureArgs.userActions = actions;
+                // Only update the saved args from the args that are set
+                r.pictureInPictureArgs.copyOnlySet(args);
                 if (r.getStack().getStackId() == PINNED_STACK_ID) {
                     // If the activity is already in picture-in-picture, update the pinned stack now
-                    mWindowManager.setPictureInPictureActions(actions);
+                    mWindowManager.setPictureInPictureAspectRatio(
+                            r.pictureInPictureArgs.getAspectRatio());
+                    mWindowManager.setPictureInPictureActions(
+                            r.pictureInPictureArgs.getActions());
                 }
             }
         } finally {
@@ -7696,14 +7699,10 @@
      * 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.
      *
-     * @param checkAspectRatio whether or not to check {@param aspectRatio} is within a valid range
-     * @param checkActivityVisibility whether or not to enforce that the activity is currently
-     *                                visible
-     *
      * @return the activity record for the given {@param token} if all the checks pass.
      */
-    private ActivityRecord ensureValidPictureInPictureActivityLocked(String caller, IBinder token,
-            float aspectRatio, boolean checkAspectRatio, boolean checkActivityVisibility) {
+    private ActivityRecord ensureValidPictureInPictureActivityArgsLocked(String caller,
+            IBinder token, PictureInPictureArgs args) {
         if (!mSupportsPictureInPicture) {
             throw new IllegalStateException(caller
                     + ": Device doesn't support picture-in-picture mode.");
@@ -7715,10 +7714,9 @@
                     + ": Can't find activity for token=" + token);
         }
 
-        if (!r.canEnterPictureInPicture(checkActivityVisibility)) {
-            throw new IllegalArgumentException(caller
-                    + ": Current activity does not support picture-in-picture or is not "
-                    + "visible r=" + r);
+        if (!r.supportsPictureInPicture()) {
+            throw new IllegalStateException(caller
+                    + ": Current activity does not support picture-in-picture.");
         }
 
         if (r.getStack().isHomeStack()) {
@@ -7726,12 +7724,20 @@
                     + ": Activities on the home stack not supported");
         }
 
-        if (checkAspectRatio && !isValidPictureInPictureAspectRatio(aspectRatio)) {
+        if (args.hasSetAspectRatio()
+                && !isValidPictureInPictureAspectRatio(args.getAspectRatio())) {
             throw new IllegalArgumentException(String.format(caller
                     + ": Aspect ratio is too extreme (must be between %f and %f).",
                             mMinPipAspectRatio, mMaxPipAspectRatio));
         }
 
+        if (args.hasSetActions()
+                && args.getActions().size() > ActivityManager.getMaxNumPictureInPictureActions()) {
+            throw new IllegalArgumentException(String.format(caller + ": Invalid number of"
+                    + "picture-in-picture actions.  Only a maximum of %d actions allowed",
+                            ActivityManager.getMaxNumPictureInPictureActions()));
+        }
+
         return r;
     }
 
@@ -8020,15 +8026,80 @@
         return readMet && writeMet;
     }
 
-    public int getAppStartMode(int uid, String packageName) {
+    public boolean isAppStartModeDisabled(int uid, String packageName) {
         synchronized (this) {
-            return checkAllowBackgroundLocked(uid, packageName, -1, false);
+            return getAppStartModeLocked(uid, packageName, 0, -1, false, true)
+                    == ActivityManager.APP_START_MODE_DISABLED;
         }
     }
 
-    int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
-            boolean alwaysRestrict) {
+    // Unified app-op and target sdk check
+    int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
+        // Apps that target O+ are always subject to background check
+        if (mEnforceBackgroundCheck && packageTargetSdk >= Build.VERSION_CODES.O) {
+            if (DEBUG_BACKGROUND_CHECK) {
+                Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
+            }
+            return ActivityManager.APP_START_MODE_DELAYED_RIGID;
+        }
+        // ...and legacy apps get an AppOp check
+        int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
+                uid, packageName);
+        if (DEBUG_BACKGROUND_CHECK) {
+            Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
+        }
+        switch (appop) {
+            case AppOpsManager.MODE_ALLOWED:
+                return ActivityManager.APP_START_MODE_NORMAL;
+            case AppOpsManager.MODE_IGNORED:
+                return ActivityManager.APP_START_MODE_DELAYED;
+            default:
+                return ActivityManager.APP_START_MODE_DELAYED_RIGID;
+        }
+    }
+
+    // Service launch is available to apps with run-in-background exemptions but
+    // some other background operations are not.  If we're doing a check
+    // 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) {
+            if (DEBUG_BACKGROUND_CHECK) {
+                Slog.i(TAG, "App " + uid + "/" + packageName
+                        + " is persistent; not restricted in background");
+            }
+            return ActivityManager.APP_START_MODE_NORMAL;
+        }
+
+        // Non-persistent but background whitelisted?
+        if (uidOnBackgroundWhitelist(uid)) {
+            if (DEBUG_BACKGROUND_CHECK) {
+                Slog.i(TAG, "App " + uid + "/" + packageName
+                        + " on background whitelist; not restricted in background");
+            }
+            return ActivityManager.APP_START_MODE_NORMAL;
+        }
+
+        // Is this app on the battery whitelist?
+        if (isOnDeviceIdleWhitelistLocked(uid)) {
+            if (DEBUG_BACKGROUND_CHECK) {
+                Slog.i(TAG, "App " + uid + "/" + packageName
+                        + " on idle whitelist; not restricted in background");
+            }
+            return ActivityManager.APP_START_MODE_NORMAL;
+        }
+
+        // None of the service-policy criteria apply, so we apply the common criteria
+        return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
+    }
+
+    int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
+            int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
         UidRecord uidRec = mActiveUids.get(uid);
+        if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+                + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+                + (uidRec != null ? uidRec.idle : false));
         if (uidRec == null || alwaysRestrict || uidRec.idle) {
             boolean ephemeral;
             if (uidRec == null) {
@@ -8042,27 +8113,49 @@
                 // We are hard-core about ephemeral apps not running in the background.
                 return ActivityManager.APP_START_MODE_DISABLED;
             } else {
-                if (callingPid >= 0) {
-                    ProcessRecord proc;
-                    synchronized (mPidsSelfLocked) {
-                        proc = mPidsSelfLocked.get(callingPid);
-                    }
-                    if (proc != null && proc.curProcState
-                            < ActivityManager.PROCESS_STATE_RECEIVER) {
-                        // Whoever is instigating this is in the foreground, so we will allow it
-                        // to go through.
-                        return ActivityManager.APP_START_MODE_NORMAL;
+                if (disabledOnly) {
+                    // The caller is only interested in whether app starts are completely
+                    // disabled for the given package (that is, it is an instant app).  So
+                    // we don't need to go further, which is all just seeing if we should
+                    // apply a "delayed" mode for a regular app.
+                    return ActivityManager.APP_START_MODE_NORMAL;
+                }
+                final int startMode = (alwaysRestrict)
+                        ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
+                        : appServicesRestrictedInBackgroundLocked(uid, packageName,
+                                packageTargetSdk);
+                if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid
+                        + " pkg=" + packageName + " startMode=" + startMode
+                        + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid));
+                if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
+                    // This is an old app that has been forced into a "compatible as possible"
+                    // mode of background check.  To increase compatibility, we will allow other
+                    // foreground apps to cause its services to start.
+                    if (callingPid >= 0) {
+                        ProcessRecord proc;
+                        synchronized (mPidsSelfLocked) {
+                            proc = mPidsSelfLocked.get(callingPid);
+                        }
+                        if (proc != null && proc.curProcState
+                                < ActivityManager.PROCESS_STATE_RECEIVER) {
+                            // Whoever is instigating this is in the foreground, so we will allow it
+                            // to go through.
+                            return ActivityManager.APP_START_MODE_NORMAL;
+                        }
                     }
                 }
-                if (mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND, uid,
-                        packageName) != AppOpsManager.MODE_ALLOWED) {
-                    return ActivityManager.APP_START_MODE_DELAYED;
-                }
+                return startMode;
             }
         }
         return ActivityManager.APP_START_MODE_NORMAL;
     }
 
+    boolean isOnDeviceIdleWhitelistLocked(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        return Arrays.binarySearch(mDeviceIdleWhitelist, appId) >= 0
+                || Arrays.binarySearch(mDeviceIdleTempWhitelist, appId) >= 0;
+    }
+
     private ProviderInfo getProviderInfoLocked(String authority, int userHandle, int pmFlags) {
         ProviderInfo pi = null;
         ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userHandle);
@@ -8079,6 +8172,12 @@
         return pi;
     }
 
+    void grantEphemeralAccessLocked(int userId, Intent intent,
+            int targetAppId, int ephemeralAppId) {
+        getPackageManagerInternalLocked().
+                grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId);
+    }
+
     private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
         final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris != null) {
@@ -9659,15 +9758,17 @@
         enforceCallingPermission(READ_FRAME_BUFFER, "getTaskSnapshot()");
         final long ident = Binder.clearCallingIdentity();
         try {
+            final TaskRecord task;
             synchronized (this) {
-                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
+                task = mStackSupervisor.anyTaskForIdLocked(
                         taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
                 if (task == null) {
                     Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
                     return null;
                 }
-                return task.getSnapshot();
             }
+            // Don't call this while holding the lock as this operation might hit the disk.
+            return task.getSnapshot();
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -11461,6 +11562,10 @@
         mCoreSettingsObserver = new CoreSettingsObserver(this);
         mFontScaleSettingObserver = new FontScaleSettingObserver();
 
+        // Now that the settings provider is published we can consider sending
+        // in a rescue party.
+        RescueParty.onSettingsProviderPublished(mContext);
+
         //mUsageStatsService.monitorPackages();
     }
 
@@ -11651,6 +11756,16 @@
         return r;
     }
 
+    private boolean uidOnBackgroundWhitelist(final int uid) {
+        final int N = mBackgroundUidWhitelist.length;
+        for (int i = 0; i < N; i++) {
+            if (uid == mBackgroundUidWhitelist[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
             String abiOverride) {
         ProcessRecord app;
@@ -14977,6 +15092,8 @@
                     }
                 }
             }
+            pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
+            pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
         }
         if (dumpPackage == null) {
             pw.println("  mWakefulness="
@@ -17284,7 +17401,8 @@
 
     @Override
     public ComponentName startService(IApplicationThread caller, Intent service,
-            String resolvedType, String callingPackage, int userId)
+            String resolvedType, int id, Notification notification,
+            String callingPackage, int userId)
             throws TransactionTooLargeException {
         enforceNotIsolatedCaller("startService");
         // Refuse possible leaked file descriptors
@@ -17303,7 +17421,8 @@
             final int callingUid = Binder.getCallingUid();
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(caller, service,
-                    resolvedType, callingPid, callingUid, callingPackage, userId);
+                    resolvedType, id, notification,
+                    callingPid, callingUid, callingPackage, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -17317,7 +17436,7 @@
                     "startServiceInPackage: " + service + " type=" + resolvedType);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(null, service,
-                    resolvedType, -1, uid, callingPackage, userId);
+                    resolvedType, 0, null, -1, uid, callingPackage, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -18176,6 +18295,13 @@
         }
 
         if (action != null) {
+            if (mBackgroundLaunchBroadcasts.contains(action)) {
+                if (DEBUG_BACKGROUND_CHECK) {
+                    Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
+                }
+                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+            }
+
             switch (action) {
                 case Intent.ACTION_UID_REMOVED:
                 case Intent.ACTION_PACKAGE_REMOVED:
@@ -19300,7 +19426,8 @@
                 UserHandle.USER_ALL);
         if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
             intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
-            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
             if (initLocale || !mProcessesReady) {
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             }
@@ -21623,12 +21750,18 @@
         for (int i=mActiveUids.size()-1; i>=0; i--) {
             final UidRecord uidRec = mActiveUids.valueAt(i);
             int uidChange = UidRecord.CHANGE_PROCSTATE;
-            if (uidRec.setProcState != uidRec.curProcState) {
+            if (uidRec.setProcState != uidRec.curProcState
+                    || uidRec.setWhitelist != uidRec.curWhitelist) {
                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                         "Changes in " + uidRec + ": proc state from " + uidRec.setProcState
-                        + " to " + uidRec.curProcState);
-                if (ActivityManager.isProcStateBackground(uidRec.curProcState)) {
-                    if (!ActivityManager.isProcStateBackground(uidRec.setProcState)) {
+                        + " to " + uidRec.curProcState + ", whitelist from " + uidRec.setWhitelist
+                        + " to " + uidRec.curWhitelist);
+                if (ActivityManager.isProcStateBackground(uidRec.curProcState)
+                        && !uidRec.curWhitelist) {
+                    // UID is now in the background (and not on the temp whitelist).  Was it
+                    // previously in the foreground (or on the temp whitelist)?
+                    if (!ActivityManager.isProcStateBackground(uidRec.setProcState)
+                            || uidRec.setWhitelist) {
                         uidRec.lastBackgroundTime = nowElapsed;
                         if (!mHandler.hasMessages(IDLE_UIDS_MSG)) {
                             // Note: the background settle time is in elapsed realtime, while
@@ -21646,6 +21779,7 @@
                     uidRec.lastBackgroundTime = 0;
                 }
                 uidRec.setProcState = uidRec.curProcState;
+                uidRec.setWhitelist = uidRec.curWhitelist;
                 enqueueUidChangeLocked(uidRec, -1, uidChange);
                 noteUidProcessState(uidRec.uid, uidRec.curProcState);
             }
@@ -21789,6 +21923,20 @@
         enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE);
     }
 
+    final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
+        boolean changed = false;
+        for (int i=mActiveUids.size()-1; i>=0; i--) {
+            final UidRecord uidRec = mActiveUids.valueAt(i);
+            if (UserHandle.getAppId(uidRec.uid) == appId && uidRec.curWhitelist != onWhitelist) {
+                uidRec.curWhitelist = onWhitelist;
+                changed = true;
+            }
+        }
+        if (changed) {
+            updateOomAdjLocked();
+        }
+    }
+
     final void trimApplications() {
         synchronized (this) {
             int i;
@@ -22494,6 +22642,21 @@
         }
 
         @Override
+        public void setDeviceIdleWhitelist(int[] appids) {
+            synchronized (ActivityManagerService.this) {
+                mDeviceIdleWhitelist = appids;
+            }
+        }
+
+        @Override
+        public void updateDeviceIdleTempWhitelist(int[] appids, int changingAppId, boolean adding) {
+            synchronized (ActivityManagerService.this) {
+                mDeviceIdleTempWhitelist = appids;
+                setAppIdTempWhitelistStateLocked(changingAppId, adding);
+            }
+        }
+
+        @Override
         public void updatePersistentConfigurationForUser(@NonNull Configuration values,
                 int userId) {
             Preconditions.checkNotNull(values, "Configuration must not be null");
@@ -22776,6 +22939,52 @@
         return mUserController.restartUser(userId, /* foreground */ false);
     }
 
+    @Override
+    public void scheduleApplicationInfoChanged(List<String> packageNames, int userId) {
+        enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+                "scheduleApplicationInfoChanged()");
+
+        synchronized (this) {
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                updateApplicationInfoLocked(packageNames, userId);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
+        final boolean updateFrameworkRes = packagesToUpdate.contains("android");
+        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+            final ProcessRecord app = mLruProcesses.get(i);
+            if (app.thread == null) {
+                continue;
+            }
+
+            if (userId != UserHandle.USER_ALL && app.userId != userId) {
+                continue;
+            }
+
+            final int packageCount = app.pkgList.size();
+            for (int j = 0; j < packageCount; j++) {
+                final String packageName = app.pkgList.keyAt(j);
+                if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
+                    try {
+                        final ApplicationInfo ai = mPackageManagerInt.getApplicationInfo(
+                                packageName, app.userId);
+                        if (ai != null) {
+                            app.thread.scheduleApplicationInfoChanged(ai);
+                        }
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, String.format("Failed to update %s ApplicationInfo for %s",
+                                    packageName, app));
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Attach an agent to the specified process (proces name or PID)
      */
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 29a4781..1a2a31b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -167,11 +167,13 @@
                     return runBugReport(pw);
                 case "force-stop":
                     return runForceStop(pw);
+                case "crash":
+                    return runCrash(pw);
                 case "kill":
                     return runKill(pw);
                 case "kill-all":
                     return runKillAll(pw);
-                case "make-idle":
+                case "make-uid-idle":
                     return runMakeIdle(pw);
                 case "monitor":
                     return runMonitor(pw);
@@ -235,6 +237,8 @@
                     return runSupportsMultiwindow(pw);
                 case "supports-split-screen-multi-window":
                     return runSupportsSplitScreenMultiwindow(pw);
+                case "update-appinfo":
+                    return runUpdateApplicationInfo(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -490,7 +494,7 @@
         pw.println("Starting service: " + intent);
         pw.flush();
         ComponentName cn = mInterface.startService(null, intent, intent.getType(),
-                SHELL_PACKAGE_NAME, mUserId);
+                -1, null, SHELL_PACKAGE_NAME, mUserId);
         if (cn == null) {
             err.println("Error: Not found; no service started.");
             return -1;
@@ -500,6 +504,9 @@
         } else if (cn.getPackageName().equals("!!")) {
             err.println("Error: " + cn.getClassName());
             return -1;
+        } else if (cn.getPackageName().equals("?")) {
+            err.println("Error: " + cn.getClassName());
+            return -1;
         }
         return 0;
     }
@@ -846,6 +853,32 @@
         return 0;
     }
 
+    int runCrash(PrintWriter pw) throws RemoteException {
+        int userId = UserHandle.USER_ALL;
+
+        String opt;
+        while ((opt=getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+
+        int pid = -1;
+        String packageName = null;
+        final String arg = getNextArgRequired();
+        // The argument is either a pid or a package name
+        try {
+            pid = Integer.parseInt(arg);
+        } catch (NumberFormatException e) {
+            packageName = arg;
+        }
+        mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash");
+        return 0;
+    }
+
     int runKill(PrintWriter pw) throws RemoteException {
         int userId = UserHandle.USER_ALL;
 
@@ -2323,6 +2356,19 @@
         return 0;
     }
 
+    int runUpdateApplicationInfo(PrintWriter pw) throws RemoteException {
+        int userid = UserHandle.parseUserArg(getNextArgRequired());
+        ArrayList<String> packages = new ArrayList<>();
+        packages.add(getNextArgRequired());
+        String packageName;
+        while ((packageName = getNextArg()) != null) {
+            packages.add(packageName);
+        }
+        mInternal.scheduleApplicationInfoChanged(packages, userid);
+        pw.println("Packages updated with most recent ApplicationInfos.");
+        return 0;
+    }
+
     private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
@@ -2462,10 +2508,15 @@
             pw.println("     --telephony: will dump only telephony sections.");
             pw.println("  force-stop [--user <USER_ID> | all | current] <PACKAGE>");
             pw.println("      Completely stop the given application package.");
+            pw.println("  crash [--user <USER_ID>] <PACKAGE|PID>");
+            pw.println("      Induce a VM crash in the specified package or process");
             pw.println("  kill [--user <USER_ID> | all | current] <PACKAGE>");
             pw.println("      Kill all processes associated with the given application.");
             pw.println("  kill-all");
             pw.println("      Kill all processes that are safe to kill (cached, etc).");
+            pw.println("  make-uid-idle [--user <USER_ID> | all | current] <PACKAGE>");
+            pw.println("      If the given application's uid is in the background and waiting to");
+            pw.println("      become idle (not allowing background services), do that now.");
             pw.println("  monitor [--gdb <port>]");
             pw.println("      Start monitoring for crashes or ANRs.");
             pw.println("      --gdb: start gdbserv on the given port at crash/ANR");
@@ -2584,6 +2635,9 @@
             pw.println("           Test command for sizing <TASK_ID> by <STEP_SIZE>");
             pw.println("           increments within the screen applying the optional [DELAY_MS] between");
             pw.println("           each step.");
+            pw.println("  update-appinfo <USER_ID> <PACKAGE_NAME> [<PACKAGE_NAME>...]");
+            pw.println("      Update the ApplicationInfo objects of the listed packages for <USER_ID>");
+            pw.println("      without restarting any processes.");
             pw.println("  write");
             pw.println("      Write all pending state to storage.");
             pw.println();
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 47c3e6f..a968e0b 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -63,9 +63,9 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManagerInternal.PictureInPictureArguments;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
+import android.app.PictureInPictureArgs;
 import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -149,6 +149,7 @@
     AppWindowContainerController mWindowContainerController;
     final ActivityInfo info; // all about me
     final ApplicationInfo appInfo; // information about activity's app
+    final int launchedFromPid; // always the pid who started the activity.
     final int launchedFromUid; // always the uid who started the activity.
     final String launchedFromPackage; // always the package who started the activity.
     final int userId;          // Which user is this running for?
@@ -229,13 +230,10 @@
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
     boolean immersive;      // immersive mode (don't interrupt if possible)
     boolean forceNewConfig; // force re-create with new config next time
-    boolean supportsPipOnMoveToBackground;   // Supports automatically entering picture-in-picture
-        // when this activity is hidden. This flag is requested by the activity.
-    private boolean enterPipOnMoveToBackground; // Flag to enter picture in picture when this
-        // activity is made invisible. This flag is set specifically when another task is being
-        // launched or moved to the front which may cause this activity to try and enter PiP
-        // when it is next made invisible.
-    PictureInPictureArguments pictureInPictureArgs = new PictureInPictureArguments();  // The PiP
+    boolean supportsPictureInPictureWhilePausing;  // This flag is set by the system to indicate
+        // that the activity can enter picture in picture while pausing (ie. only when another
+        // task is brought to front or started)
+    PictureInPictureArgs pictureInPictureArgs = new PictureInPictureArgs();  // The PiP
         // arguments used when deferring the entering of picture-in-picture.
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last launch of this activity
@@ -453,12 +451,8 @@
         if (info != null) {
             pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
         }
-        if (supportsPipOnMoveToBackground) {
-            pw.println(prefix + "supportsPipOnMoveToBackground=1");
-            pw.println(prefix + "enterPipOnMoveToBackground=" +
-                    (enterPipOnMoveToBackground ? 1 : 0));
-            pictureInPictureArgs.dump(pw, prefix);
-        }
+        pw.println(prefix + "supportsPictureInPictureWhilePausing: "
+                + supportsPictureInPictureWhilePausing);
     }
 
     private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
@@ -595,7 +589,7 @@
         return ResolverActivity.class.getName().equals(realActivity.getClassName());
     }
 
-    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
+    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,
             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
             ActivityRecord _resultTo, String _resultWho, int _reqCode,
@@ -605,6 +599,7 @@
         service = _service;
         appToken = new Token(this);
         info = aInfo;
+        launchedFromPid = _launchedFromPid;
         launchedFromUid = _launchedFromUid;
         launchedFromPackage = _launchedFromPackage;
         userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
@@ -819,23 +814,6 @@
     }
 
     /**
-     * If this activity has requested that it auto-enter picture-in-picture and we can actually do
-     * this, then mark it to enter picture in picture at that point.
-     */
-    void setEnterPipOnMoveToBackground(boolean enterPipOnInvisible) {
-        if (supportsPipOnMoveToBackground) {
-            enterPipOnMoveToBackground = enterPipOnInvisible;
-        }
-    }
-
-    /**
-     * @return whether to enter PiP when this activity is made invisible.
-     */
-    public boolean shouldEnterPictureInPictureOnInvisible() {
-        return enterPipOnMoveToBackground;
-    }
-
-    /**
      * @return Stack value from current task, null if there is no task.
      */
     ActivityStack getStack() {
@@ -918,24 +896,34 @@
     }
 
     /**
-     * @return whether this activity is currently allowed to enter PIP, if
-     * {@param checkActivityVisibility} is set, then the current activity visibility is taken into
-     * account.
+     * @return whether this activity is currently allowed to enter PIP, throwing an exception if
+     *         the activity is not currently visible.
      */
-    boolean canEnterPictureInPicture(boolean checkActivityVisibility) {
-        if (!checkActivityVisibility) {
-            return supportsPictureInPicture();
+    boolean checkEnterPictureInPictureState(String caller) {
+        boolean isKeyguardLocked = service.isKeyguardLocked();
+        boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
+        switch (state) {
+            case RESUMED:
+                // When visible, allow entering PiP if not on the lockscreen.  If there is another
+                // PiP activity, the logic to handle that comes later in enterPictureInPictureMode()
+                return !isKeyguardLocked;
+            case PAUSING:
+            case PAUSED:
+                // When pausing, only allow enter PiP if not on the lockscreen and there is not
+                // already an existing PiP activity
+                return !isKeyguardLocked && !hasPinnedStack && supportsPictureInPictureWhilePausing;
+            case STOPPING:
+                // When stopping in a valid state, then only allow enter PiP as in the pause state.
+                // Otherwise, fall through to throw an exception if the caller is trying to enter
+                // PiP in an invalid stopping state.
+                if (supportsPictureInPictureWhilePausing) {
+                    return !isKeyguardLocked && !hasPinnedStack;
+                }
+            default:
+                throw new IllegalStateException(caller
+                        + ": Current activity is not visible (state=" + state.name() + ") "
+                        + "r=" + this);
         }
-
-        if (supportsPictureInPicture()) {
-            switch (state) {
-                case RESUMED:
-                case PAUSING:
-                case PAUSED:
-                    return true;
-            }
-        }
-        return false;
     }
 
     boolean canGoInDockedStack() {
@@ -1802,6 +1790,9 @@
     }
 
     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
+        if (mWindowContainerController == null) {
+            return;
+        }
         final CompatibilityInfo compatInfo =
                 service.compatibilityInfoForPackageLocked(info.applicationInfo);
         final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
@@ -2203,9 +2194,11 @@
             throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
                     " resolvedType=" + resolvedType);
         }
-        final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
-                launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
-                null, null, 0, componentSpecified, false, stackSupervisor, null, null, null);
+        final ActivityRecord r = new ActivityRecord(service, null /* caller */,
+                0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, intent, resolvedType,
+                aInfo, service.getConfiguration(), null /* resultTo */, null /* resultWho */,
+                0 /* reqCode */, componentSpecified, false /* rootVoiceInteraction */,
+                stackSupervisor, null /* container */, null /* options */, null /* sourceRecord */);
 
         r.persistentState = persistentState;
         r.taskDescription = taskDescription;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4df0cb1..d7b3728e 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -105,6 +105,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -195,6 +196,12 @@
         return mActivityContainer.mActivityDisplay;
     }
 
+    @Override
+    void onParentChanged() {
+        super.onParentChanged();
+        mStackSupervisor.updateUIDsPresentOnDisplay();
+    }
+
     enum ActivityState {
         INITIALIZING,
         RESUMED,
@@ -680,6 +687,27 @@
         return null;
     }
 
+    boolean isInStackLocked(TaskRecord task) {
+        return mTaskHistory.contains(task);
+    }
+
+    /** Checks if there are tasks with specific UID in the stack. */
+    boolean isUidPresent(int uid) {
+        for (TaskRecord task : mTaskHistory) {
+            if (task.effectiveUid == uid) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Get all UIDs that are present in the stack. */
+    void getPresentUIDs(IntArray presentUIDs) {
+        for (TaskRecord task : mTaskHistory) {
+            presentUIDs.add(task.effectiveUid);
+        }
+    }
+
     final boolean updateLRUListLocked(ActivityRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
@@ -1698,9 +1726,7 @@
                                 + stackInvisible + " behindFullscreenActivity="
                                 + behindFullscreenActivity + " mLaunchTaskBehind="
                                 + r.mLaunchTaskBehind);
-                        if (!enterPictureInPictureOnActivityInvisible(r)) {
-                            makeInvisible(r, visibleBehind);
-                        }
+                        makeInvisible(r, visibleBehind);
                     }
                 }
                 if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
@@ -1859,35 +1885,6 @@
         return false;
     }
 
-    /**
-     * Attempts to enter picture-in-picture if the activity that is being made invisible supports
-     * it.  If not, then
-     *
-     * @return whether or not picture-in-picture mode was entered.
-     */
-    private boolean enterPictureInPictureOnActivityInvisible(ActivityRecord r) {
-        final boolean hasPinnedStack =
-                mStackSupervisor.getStack(PINNED_STACK_ID) != null;
-        final boolean isKeyguardLocked = mService.isKeyguardLocked();
-        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, " enterPictureInPictureOnInvisible="
-                + r.shouldEnterPictureInPictureOnInvisible()
-                + " hasPinnedStack=" + hasPinnedStack
-                + " isKeyguardLocked=" + isKeyguardLocked);
-        if (!hasPinnedStack && !isKeyguardLocked && r.visible &&
-                r.shouldEnterPictureInPictureOnInvisible()) {
-            r.setEnterPipOnMoveToBackground(false);
-
-            // Enter picture in picture, but don't move the home stack to the front
-            // since it will affect the focused stack's visibility and occlude
-            // starting activities
-            mService.enterPictureInPictureModeLocked(r, r.getDisplayId(),
-                    r.pictureInPictureArgs, false /* moveHomeStackToFront */,
-                    "ensureActivitiesVisibleLocked");
-            return true;
-        }
-        return false;
-    }
-
     private void makeInvisible(ActivityRecord r, ActivityRecord visibleBehind) {
         if (!r.visible) {
             if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
@@ -1906,6 +1903,10 @@
                                 "Scheduling invisibility: " + r);
                         r.app.thread.scheduleWindowVisibility(r.appToken, false);
                     }
+
+                    // Reset the flag indicating that an app can enter picture-in-picture once the
+                    // activity is hidden
+                    r.supportsPictureInPictureWhilePausing = false;
                     break;
 
                 case INITIALIZING:
@@ -2187,15 +2188,16 @@
 
         mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
 
-        // We need to start pausing the current activity so the top one can be resumed...
-        final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
-        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
+        // If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
+        // to be paused, while at the same time resuming the new resume activity
+        final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
+        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
         if (mResumedActivity != null) {
             if (DEBUG_STATES) Slog.d(TAG_STATES,
                     "resumeTopActivityLocked: Pausing " + mResumedActivity);
-            pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
+            pausing |= startPausingLocked(userLeaving, false, next, false);
         }
-        if (pausing) {
+        if (pausing && !resumeWhilePausing) {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
                     "resumeTopActivityLocked: Skip resume: need to start pausing");
             // At this point we want to put the upcoming activity's process
@@ -2696,10 +2698,10 @@
                     if (r.mLaunchTaskBehind) {
                         transit = TRANSIT_TASK_OPEN_BEHIND;
                     } else {
-                        // If a new task is being launched, then mark the existing top activity to
-                        // enter picture-in-picture if it supports auto-entering PiP
+                        // If a new task is being launched, then mark the existing top activity as
+                        // supporting picture-in-picture while pausing
                         if (focusedTopActivity != null) {
-                            focusedTopActivity.setEnterPipOnMoveToBackground(true);
+                            focusedTopActivity.supportsPictureInPictureWhilePausing = true;
                         }
                         transit = TRANSIT_TASK_OPEN;
                     }
@@ -4245,10 +4247,10 @@
         } else {
             updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
         }
-        // If a new task is moved to the front, then mark the existing top activity to enter
-        // picture-in-picture if it supports auto-entering PiP
+        // If a new task is moved to the front, then mark the existing top activity as supporting
+        // picture-in-picture while paused
         if (focusedTopActivity != null) {
-            focusedTopActivity.setEnterPipOnMoveToBackground(true);
+            focusedTopActivity.supportsPictureInPictureWhilePausing = true;
         }
 
         mStackSupervisor.resumeFocusedStackTopActivityLocked();
@@ -4904,13 +4906,13 @@
         final boolean toTop = position >= mTaskHistory.size();
         final ActivityStack prevStack = preAddTask(task, reason, toTop);
 
+        mTaskHistory.add(position, task);
         task.setStack(this);
 
         if (toTop) {
             updateTaskReturnToForTopInsertion(task);
         }
 
-        mTaskHistory.add(position, task);
         updateTaskMovement(task, toTop);
 
         postAddTask(task, prevStack);
@@ -4927,8 +4929,8 @@
 
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
-        task.setStack(this);
         insertTaskAtPosition(task, index);
+        task.setStack(this);
         postAddTask(task, null /* prevStack */);
 
         if (wasResumed) {
@@ -4966,8 +4968,8 @@
         }
     }
 
-    void moveToFrontAndResumeStateIfNeeded(
-            ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+    void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
+            boolean setPause, String reason) {
         if (!moveToFront) {
             return;
         }
@@ -4978,6 +4980,10 @@
         if (setResume) {
             mResumedActivity = r;
         }
+        // If the activity was previously pausing, then ensure we transfer that as well
+        if (setPause) {
+            mPausingActivity = r;
+        }
         // Move the stack in which we are placing the activity to the front. The call will also
         // make sure the activity focus is set.
         moveToFront(reason);
@@ -4998,6 +5004,7 @@
         final boolean wasFocused = mStackSupervisor.isFocusedStack(prevStack)
                 && (mStackSupervisor.topRunningActivityLocked() == r);
         final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+        final boolean wasPaused = prevStack.mPausingActivity == r;
 
         final TaskRecord task = createTaskRecord(
                 mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
@@ -5005,10 +5012,14 @@
         r.setTask(task, null);
         task.addActivityToTop(r);
         mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
-        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, wasPaused,
+                "moveActivityToStack");
         if (wasResumed) {
             prevStack.mResumedActivity = null;
         }
+        if (wasPaused) {
+            prevStack.mPausingActivity = null;
+        }
     }
 
     public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4fe8939..14899b4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -125,6 +125,7 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
@@ -154,6 +155,7 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -380,7 +382,10 @@
     /** Mapping from displayId to display current state */
     private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>();
 
-    InputManagerInternal mInputManagerInternal;
+    private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
+
+    private DisplayManagerInternal mDisplayManagerInternal;
+    private InputManagerInternal mInputManagerInternal;
 
     /** The chain of tasks in lockTask mode. The current frontmost task is at the top, and tasks
      * may be finished until there is only one entry left. If this is empty the system is not
@@ -580,6 +585,7 @@
             mDisplayManager =
                     (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
             mDisplayManager.registerDisplayListener(this, null);
+            mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
 
             Display[] displays = mDisplayManager.getDisplays();
             for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
@@ -1452,7 +1458,7 @@
             ActivityRecord resultRecord, ActivityStack resultStack, ActivityOptions options) {
         final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
                 callingUid);
-        if (startAnyPerm ==  PERMISSION_GRANTED) {
+        if (startAnyPerm == PERMISSION_GRANTED) {
             return true;
         }
         final int componentRestriction = getComponentRestrictionForCallingPackage(
@@ -1519,25 +1525,76 @@
             // Check if someone tries to launch an activity on a private display with a different
             // owner.
             final int launchDisplayId = options.getLaunchDisplayId();
-            if (launchDisplayId != INVALID_DISPLAY) {
-                final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId);
-                if (activityDisplay != null
-                        && (activityDisplay.mDisplay.getFlags() & FLAG_PRIVATE) != 0) {
-                    if (activityDisplay.mDisplay.getOwnerUid() != callingUid) {
-                        final String msg = "Permission Denial: starting " + intent.toString()
-                                + " from " + callerApp + " (pid=" + callingPid
-                                + ", uid=" + callingUid + ") with launchDisplayId="
-                                + launchDisplayId;
-                        Slog.w(TAG, msg);
-                        throw new SecurityException(msg);
-                    }
-                }
+            if (launchDisplayId != INVALID_DISPLAY
+                    && !isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, launchDisplayId)) {
+                final String msg = "Permission Denial: starting " + intent.toString()
+                        + " from " + callerApp + " (pid=" + callingPid
+                        + ", uid=" + callingUid + ") with launchDisplayId="
+                        + launchDisplayId;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
             }
         }
 
         return true;
     }
 
+    /** Check if caller is allowed to launch activities on specified display. */
+    boolean isCallerAllowedToLaunchOnDisplay(int callingPid, int callingUid, int launchDisplayId) {
+        if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check: displayId=" + launchDisplayId
+                + " callingPid=" + callingPid + " callingUid=" + callingUid);
+
+        final ActivityDisplay activityDisplay = mActivityDisplays.get(launchDisplayId);
+        if (activityDisplay == null) {
+            Slog.w(TAG, "Launch on display check: display not found");
+            return false;
+        }
+
+        if (!activityDisplay.isPrivate()) {
+            // Anyone can launch on a public display.
+            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+                    + " allow launch on public display");
+            return true;
+        }
+
+        // Check if the caller is the owner of the display.
+        if (activityDisplay.mDisplay.getOwnerUid() == callingUid) {
+            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+                    + " allow launch for owner of the display");
+            return true;
+        }
+
+        // Check if caller is present on display
+        if (activityDisplay.isUidPresent(callingUid)) {
+            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+                    + " allow launch for caller present on the display");
+            return true;
+        }
+
+        // Check if the caller can launch anything.
+        final int startAnyPerm = mService.checkPermission(START_ANY_ACTIVITY, callingPid,
+                callingUid);
+        if (startAnyPerm == PERMISSION_GRANTED) {
+            if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+                    + " allow launch any on display");
+            return true;
+        }
+
+        Slog.w(TAG, "Launch on display check: denied");
+        return false;
+    }
+
+    /** Update lists of UIDs that are present on displays and have access to them. */
+    void updateUIDsPresentOnDisplay() {
+        mDisplayAccessUIDs.clear();
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
+            mDisplayAccessUIDs.append(activityDisplay.mDisplayId, activityDisplay.getPresentUIDs());
+        }
+        // Store updated lists in DisplayManager. Callers from outside of AM should get them there.
+        mDisplayManagerInternal.setDisplayAccessUIDs(mDisplayAccessUIDs);
+    }
+
     UserInfo getUserInfo(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -2617,6 +2674,7 @@
         final ActivityStack prevStack = task.getStack();
         final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
         final boolean wasResumed = prevStack.mResumedActivity == r;
+        final boolean wasPaused = prevStack.mPausingActivity == r;
         // In some cases the focused stack isn't the front stack. E.g. pinned stack.
         // Whenever we are moving the top activity from the front stack we want to make sure to move
         // the stack to the front.
@@ -2641,10 +2699,19 @@
         task.mTemporarilyUnresizable = false;
         task.reparent(stack.mStackId, toTop ? MAX_VALUE : 0, reason);
 
+        // Reset the resumed activity on the previous stack
+        if (wasResumed) {
+            prevStack.mResumedActivity = null;
+        }
+        // Reset the paused activity on the previous stack
+        if (wasPaused) {
+            prevStack.mPausingActivity = null;
+        }
+
         // If the task had focus before (or we're requested to move focus),
         // move focus to the new stack by moving the stack to the front.
-        stack.moveToFrontAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
+        stack.moveToFrontAndResumeStateIfNeeded(r, forceFocus || wasFocused || wasFront, wasResumed,
+                wasPaused, reason);
 
         return stack;
     }
@@ -2795,8 +2862,12 @@
 
             if (task.mActivities.size() == 1) {
                 // There is only one activity in the task. So, we can just move the task over to
-                // the stack without re-parenting the activity in a different task.
-                if (moveHomeStackToFront && task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+                // the stack without re-parenting the activity in a different task.  We don't
+                // move the home stack forward if we are currently entering picture-in-picture
+                // while pausing because that changes the focused stack and may prevent the new
+                // starting activity from resuming.
+                if (moveHomeStackToFront && task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE
+                        && !r.supportsPictureInPictureWhilePausing) {
                     // Move the home stack forward if the task we just moved to the pinned stack
                     // was launched from home so home should be visible behind it.
                     moveHomeStackToFront(reason);
@@ -2808,6 +2879,10 @@
                 // reveal/leave the other activities in their original task
                 stack.moveActivityToStack(r);
             }
+
+            // Reset the state that indicates it can enter PiP while pausing after we've moved it
+            // to the pinned stack
+            r.supportsPictureInPictureWhilePausing = false;
         } finally {
             mWindowManager.continueSurfaceLayout();
         }
@@ -4568,6 +4643,9 @@
 
         ActivityRecord mVisibleBehindActivity;
 
+        /** Array of all UIDs that are present on the display. */
+        private IntArray mDisplayAccessUIDs = new IntArray();
+
         ActivityDisplay() {
         }
 
@@ -4630,6 +4708,28 @@
         protected ConfigurationContainer getParent() {
             return ActivityStackSupervisor.this;
         }
+
+        boolean isPrivate() {
+            return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
+        }
+
+        boolean isUidPresent(int uid) {
+            for (ActivityStack stack : mStacks) {
+                if (stack.isUidPresent(uid)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /** Update and get all UIDs that are present on the display and have access to it. */
+        private IntArray getPresentUIDs() {
+            mDisplayAccessUIDs.clear();
+            for (ActivityStack stack : mStacks) {
+                stack.getPresentUIDs(mDisplayAccessUIDs);
+            }
+            return mDisplayAccessUIDs;
+        }
     }
 
     class VirtualActivityDisplay extends ActivityDisplay {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2634385..26d2ee2 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -476,10 +476,10 @@
             aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
         }
 
-        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
-                intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord,
-                resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor,
-                container, options, sourceRecord);
+        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
+                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
+                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
+                mSupervisor, container, options, sourceRecord);
         if (outActivity != null) {
             outActivity[0] = r;
         }
@@ -582,7 +582,10 @@
             // The activity was already running in the pinned stack so it wasn't started, but either
             // brought to the front or the new intent was delivered to it since it was already in
             // front. Notify anyone interested in this piece of information.
-            mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt();
+            final ComponentName sourceComponent = sourceRecord == null ? null :
+                    sourceRecord.realActivity;
+            mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(
+                    sourceComponent);
             return;
         }
     }
@@ -1128,7 +1131,8 @@
 
         mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                 mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
-
+        mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
+                mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
         if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
             mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
         }
@@ -1896,16 +1900,14 @@
 
         final ActivityStack currentStack = task != null ? task.getStack() : null;
         if (currentStack != null) {
-            if (currentStack.isOnHomeDisplay()) {
-                if (mSupervisor.mFocusedStack != currentStack) {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Setting " + "focused stack to r=" + r
-                                    + " task=" + task);
-                } else {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Focused stack already="
-                                    + mSupervisor.mFocusedStack);
-                }
+            if (mSupervisor.mFocusedStack != currentStack) {
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Setting " + "focused stack to r=" + r
+                                + " task=" + task);
+            } else {
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Focused stack already="
+                                + mSupervisor.mFocusedStack);
             }
             return currentStack;
         }
@@ -1922,13 +1924,7 @@
         // Same also applies to dynamic stacks, as they behave similar to fullscreen stack.
         // If the freeform or docked stack has focus, and the activity to be launched is resizeable,
         // we can also put it in the focused stack.
-        final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
-        final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
-                || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack())
-                || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced())
-                || isDynamicStack(focusedStackId);
-        if (canUseFocusedStack && (!newTask
-                || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
+        if (canLaunchIntoFocusedStack(r, newTask)) {
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                     "computeStackFocus: Have a focused stack=" + mSupervisor.mFocusedStack);
             return mSupervisor.mFocusedStack;
@@ -1955,6 +1951,36 @@
         return stack;
     }
 
+    /** Check if provided activity record can launch in currently focused stack. */
+    private boolean canLaunchIntoFocusedStack(ActivityRecord r, boolean newTask) {
+        // The fullscreen stack can contain any task regardless of if the task is resizeable
+        // or not. So, we let the task go in the fullscreen task if it is the focus stack.
+        // Same also applies to dynamic stacks, as they behave similar to fullscreen stack.
+        // If the freeform or docked stack has focus, and the activity to be launched is resizeable,
+        // we can also put it in the focused stack.
+        final ActivityStack focusedStack = mSupervisor.mFocusedStack;
+        final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
+        final boolean canUseFocusedStack;
+        switch (focusedStackId) {
+            case FULLSCREEN_WORKSPACE_STACK_ID:
+                canUseFocusedStack = true;
+                break;
+            case DOCKED_STACK_ID:
+                canUseFocusedStack = r.canGoInDockedStack();
+                break;
+            case FREEFORM_WORKSPACE_STACK_ID:
+                canUseFocusedStack = r.isResizeableOrForced();
+                break;
+            default:
+                canUseFocusedStack = isDynamicStack(focusedStackId)
+                        && mSupervisor.isCallerAllowedToLaunchOnDisplay(r.launchedFromPid,
+                        r.launchedFromUid, focusedStack.mDisplayId);
+        }
+
+        return canUseFocusedStack
+                && (!newTask || focusedStack.mActivityContainer.isEligibleForNewTasks());
+    }
+
     private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
             ActivityOptions aOptions) {
 
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 029b5dd..384f2f8 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -20,6 +20,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.os.ProcessCpuTracker;
+import com.android.server.RescueParty;
 import com.android.server.Watchdog;
 
 import android.app.ActivityManager;
@@ -258,7 +259,16 @@
         }
     }
 
-    void scheduleAppCrashLocked(int uid, int initialPid, String packageName,
+    /**
+     * Induce a crash in the given app.
+     *
+     * @param uid if nonnegative, the required matching uid of the target to crash
+     * @param initialPid fast-path match for the target to crash
+     * @param packageName fallback match if the stated pid is not found or doesn't match uid
+     * @param userId If nonnegative, required to identify a match by package name
+     * @param message
+     */
+    void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
             String message) {
         ProcessRecord proc = null;
 
@@ -269,14 +279,15 @@
         synchronized (mService.mPidsSelfLocked) {
             for (int i=0; i<mService.mPidsSelfLocked.size(); i++) {
                 ProcessRecord p = mService.mPidsSelfLocked.valueAt(i);
-                if (p.uid != uid) {
+                if (uid >= 0 && p.uid != uid) {
                     continue;
                 }
                 if (p.pid == initialPid) {
                     proc = p;
                     break;
                 }
-                if (p.pkgList.containsKey(packageName)) {
+                if (p.pkgList.containsKey(packageName)
+                        && (userId < 0 || p.userId == userId)) {
                     proc = p;
                 }
             }
@@ -285,7 +296,8 @@
         if (proc == null) {
             Slog.w(TAG, "crashApplication: nothing for uid=" + uid
                     + " initialPid=" + initialPid
-                    + " packageName=" + packageName);
+                    + " packageName=" + packageName
+                    + " userId=" + userId);
             return;
         }
 
@@ -323,6 +335,12 @@
             longMsg = shortMsg;
         }
 
+        // If a persistent app is stuck in a crash loop, the device isn't very
+        // usable, so we want to consider sending out a rescue party.
+        if (r != null && r.persistent) {
+            RescueParty.notePersistentAppCrash(mContext, r.uid);
+        }
+
         AppErrorResult result = new AppErrorResult();
         TaskRecord task;
         synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 8104a43..ee2467a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -592,22 +592,6 @@
                     + " (uid " + r.callingUid + ")");
             skip = true;
         }
-        if (!skip) {
-            final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
-                    filter.packageName, -1, false);
-            if (false && allowed == ActivityManager.APP_START_MODE_DISABLED) {
-                // XXX should we really not allow this?  It means that while we are
-                // keeping an ephemeral app cached, its registered receivers will stop
-                // receiving broadcasts after it goes idle...  so if it comes back to
-                // the foreground, it won't know what the current state of those broadcasts is.
-                Slog.w(TAG, "Background execution not allowed: receiving "
-                        + r.intent
-                        + " to " + filter.receiverList.app
-                        + " (pid=" + filter.receiverList.pid
-                        + ", uid=" + filter.receiverList.uid + ")");
-                skip = true;
-            }
-        }
 
         if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
                 r.callingPid, r.resolvedType, filter.receiverList.uid)) {
@@ -1156,14 +1140,14 @@
                     info.activityInfo.applicationInfo.uid, false);
 
             if (!skip) {
-                final int allowed = mService.checkAllowBackgroundLocked(
-                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1,
-                        true);
+                final int allowed = mService.getAppStartModeLocked(
+                        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
+                        info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false);
                 if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                     // We won't allow this receiver to be launched if the app has been
                     // completely disabled from launches, or it was not explicitly sent
                     // to it and the app is in a state that should not receive it
-                    // (depending on how checkAllowBackgroundLocked has determined that).
+                    // (depending on how getAppStartModeLocked has determined that).
                     if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                         Slog.w(TAG, "Background execution disabled: receiving "
                                 + r.intent + " to "
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index e2870d8..9348023 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -20,7 +20,6 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructTimeval;
-import android.system.StructUcred;
 import android.system.UnixSocketAddress;
 import android.util.Slog;
 
@@ -105,9 +104,9 @@
 
         if (DEBUG) Slog.i(TAG, "Starting up");
 
-        // The file system entity for this socket is created with 0700 perms, owned
-        // by system:system.  debuggerd runs as root, so is capable of connecting to
-        // it, but 3rd party apps cannot.
+        // The file system entity for this socket is created with 0777 perms, owned
+        // by system:system. selinux restricts things so that only crash_dump can
+        // access it.
         {
             File socketFile = new File(DEBUGGERD_SOCKET_PATH);
             if (socketFile.exists()) {
@@ -121,6 +120,7 @@
                     DEBUGGERD_SOCKET_PATH);
             Os.bind(serverFd, sockAddr);
             Os.listen(serverFd, 1);
+            Os.chmod(DEBUGGERD_SOCKET_PATH, 0777);
 
             while (true) {
                 FileDescriptor peerFd = null;
@@ -129,19 +129,14 @@
                     peerFd = Os.accept(serverFd, null /* peerAddress */);
                     if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
                     if (peerFd != null) {
-                        // Only the superuser is allowed to talk to us over this socket
-                        StructUcred credentials =
-                                Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
-                        if (credentials.uid == 0) {
-                            // the reporting thread may take responsibility for
-                            // acking the debugger; make sure we play along.
-                            consumeNativeCrashData(peerFd);
-                        }
+                        // the reporting thread may take responsibility for
+                        // acking the debugger; make sure we play along.
+                        consumeNativeCrashData(peerFd);
                     }
                 } catch (Exception e) {
                     Slog.w(TAG, "Error handling connection", e);
                 } finally {
-                    // Always ack debuggerd's connection to us.  The actual
+                    // Always ack crash_dump's connection to us.  The actual
                     // byte written is irrelevant.
                     if (peerFd != null) {
                         try {
@@ -194,7 +189,7 @@
         return totalRead;
     }
 
-    // Read the crash report from the debuggerd connection
+    // Read a crash report from the connection
     void consumeNativeCrashData(FileDescriptor fd) {
         if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
         final byte[] buf = new byte[4096];
@@ -205,6 +200,10 @@
             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
 
+            // The socket is guarded by an selinux neverallow rule that only
+            // permits crash_dump to connect to it. This allows us to trust the
+            // received values.
+
             // first, the pid and signal number
             int headerBytes = readExactly(fd, buf, 0, 8);
             if (headerBytes != 8) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 71c7fd3..82b00da 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -534,7 +534,7 @@
                         // get to be foreground.
                         ams.setServiceForeground(name, ServiceRecord.this,
                                 0, null, 0);
-                        ams.crashApplication(appUid, appPid, localPackageName,
+                        ams.crashApplication(appUid, appPid, localPackageName, -1,
                                 "Bad notification for startForeground: " + e);
                     }
                 }
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index cb20eac..2990dff 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ITaskStackListener;
 import android.app.ActivityManager.TaskDescription;
 import android.content.ComponentName;
@@ -43,6 +45,7 @@
     static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
     static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
     static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
+    static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
 
     // Delay in notifying task stack change listeners (in millis)
     static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -94,7 +97,7 @@
     };
 
     private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> {
-        l.onPinnedActivityRestartAttempt();
+        l.onPinnedActivityRestartAttempt((ComponentName) m.obj);
     };
 
     private final TaskStackConsumer mNotifyPinnedStackAnimationEnded = (l, m) -> {
@@ -113,6 +116,10 @@
         l.onTaskProfileLocked(m.arg1, m.arg2);
     };
 
+    private final TaskStackConsumer mNotifyTaskSnapshotChanged = (l, m) -> {
+        l.onTaskSnapshotChanged(m.arg1, (TaskSnapshot) m.obj);
+    };
+
     @FunctionalInterface
     public interface TaskStackConsumer {
         void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -170,7 +177,9 @@
                     break;
                 case NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG:
                     forAllRemoteListeners(mNotifyTaskProfileLocked, msg);
-
+                    break;
+                case NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG:
+                    forAllRemoteListeners(mNotifyTaskSnapshotChanged, msg);
                     break;
             }
         }
@@ -258,10 +267,11 @@
      * running in the pinned stack and the activity was not actually started, but the task is
      * either brought to the front or a new Intent is delivered to it.
      */
-    void notifyPinnedActivityRestartAttempt() {
+    void notifyPinnedActivityRestartAttempt(ComponentName sourceComponent) {
         mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
         final Message msg =
-                mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
+                mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
+                        sourceComponent);
         forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg);
         msg.sendToTarget();
     }
@@ -348,4 +358,14 @@
         forAllLocalListeners(mNotifyTaskProfileLocked, msg);
         msg.sendToTarget();
     }
+
+    /**
+     * Notify listeners that the snapshot of a task has changed.
+     */
+    void notifyTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG,
+                taskId, 0, snapshot);
+        forAllLocalListeners(mNotifyTaskSnapshotChanged, msg);
+        msg.sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 7a62f2c..9dde39e 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -651,6 +651,8 @@
                                         "omitting from persistentTaskIds task=" + task);
                             }
                         }
+                        mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
+                                mRecentTasks.usersWithRecentsLoadedLocked());
                     }
                     removeObsoleteFiles(persistentTaskIds);
                 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4c4c444..1f5152a 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -52,6 +52,8 @@
 import com.android.internal.util.XmlUtils;
 
 import com.android.server.wm.TaskWindowContainerController;
+import com.android.server.wm.TaskWindowContainerListener;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -105,7 +107,7 @@
 import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 
-final class TaskRecord extends ConfigurationContainer {
+final class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -412,8 +414,8 @@
 
         final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
         final Configuration overrideConfig = getOverrideConfiguration();
-        mWindowContainerController = new TaskWindowContainerController(taskId, getStackId(), userId,
-                bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
+        mWindowContainerController = new TaskWindowContainerController(taskId, this, getStackId(),
+                userId, bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
                 showForAllUsers);
     }
 
@@ -429,6 +431,11 @@
         mWindowContainerController = null;
     }
 
+    @Override
+    public void onSnapshotChanged(TaskSnapshot snapshot) {
+        mService.mTaskChangeNotificationController.notifyTaskSnapshotChanged(taskId, snapshot);
+    }
+
     void setResizeMode(int resizeMode) {
         if (mResizeMode == resizeMode) {
             return;
@@ -576,11 +583,14 @@
         mWindowContainerController.cancelThumbnailTransition();
     }
 
-    public TaskSnapshot getSnapshot() {
-        if (mWindowContainerController == null) {
-            return null;
-        }
-        return mWindowContainerController.getSnapshot();
+    /**
+     * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
+     */
+    TaskSnapshot getSnapshot() {
+
+        // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
+        // synchronized between AM and WM.
+        return mService.mWindowManager.getTaskSnapshot(taskId, userId);
     }
 
     void touchActiveTime() {
@@ -734,8 +744,14 @@
         return mStack;
     }
 
-    /** Must be used for setting parent stack because it performs configuration updates. */
+    /**
+     * Must be used for setting parent stack because it performs configuration updates.
+     * Must be called after adding task as a child to the stack.
+     */
     void setStack(ActivityStack stack) {
+        if (stack != null && !stack.isInStackLocked(this)) {
+            throw new IllegalStateException("Task must be added as a Stack child first.");
+        }
         mStack = stack;
         onParentChanged();
     }
@@ -762,6 +778,12 @@
         return mStack;
     }
 
+    @Override
+    void onParentChanged() {
+        super.onParentChanged();
+        mService.mStackSupervisor.updateUIDsPresentOnDisplay();
+    }
+
     // Close up recents linked list.
     void closeRecentsChain() {
         if (mPrevAffiliate != null) {
@@ -781,6 +803,9 @@
             inRecents = false;
             mService.notifyTaskPersisterLocked(this, false);
         }
+
+        // TODO: Use window container controller once tasks are better synced between AM and WM
+        mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId);
     }
 
     void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index d1a15bd..64e3417 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -26,10 +26,13 @@
  */
 public final class UidRecord {
     final int uid;
+    final boolean persistent;
     int curProcState;
     int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
     long lastBackgroundTime;
     boolean ephemeral;
+    boolean curWhitelist;
+    boolean setWhitelist;
     boolean idle;
     int numProcs;
 
@@ -49,8 +52,9 @@
 
     ChangeItem pendingChange;
 
-    public UidRecord(int _uid) {
+    public UidRecord(int _uid, boolean _persist) {
         uid = _uid;
+        persistent = _persist;
         reset();
     }
 
@@ -69,6 +73,9 @@
         if (ephemeral) {
             sb.append(" ephemeral");
         }
+        if (curWhitelist) {
+            sb.append(" whitelist");
+        }
         if (lastBackgroundTime > 0) {
             sb.append(" bg:");
             TimeUtils.formatDuration(SystemClock.elapsedRealtime()-lastBackgroundTime, sb);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 71ebad9..728476a 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -47,6 +47,7 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.Dialog;
 import android.app.IStopUserCallback;
@@ -55,6 +56,7 @@
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.BatteryStats;
@@ -255,10 +257,17 @@
             // storage is already unlocked.
             if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
                 mInjector.getUserManagerInternal().setUserState(userId, uss.state);
-                if (!mInjector.isRuntimeRestarted() && !mInjector.isFirstBoot()) {
+                // Do not report secondary users, runtime restarts or first boot/upgrade
+                if (userId == UserHandle.USER_SYSTEM
+                        && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
                     int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
                     MetricsLogger.histogram(mInjector.getContext(),
                             "framework_locked_boot_completed", uptimeSeconds);
+                    final int MAX_UPTIME_SECONDS = 120;
+                    if (uptimeSeconds > MAX_UPTIME_SECONDS) {
+                        Slog.wtf("SystemServerTiming",
+                                "finishUserBoot took too long. uptimeSeconds=" + uptimeSeconds);
+                    }
                 }
 
                 mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
@@ -414,7 +423,8 @@
                 if (userId != UserHandle.USER_SYSTEM) {
                     Slog.d(TAG, "Initializing user #" + userId);
                     Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
-                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+                            | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                     mInjector.broadcastIntentLocked(intent, null,
                             new IIntentReceiver.Stub() {
                                 @Override
@@ -430,7 +440,9 @@
             }
 
             Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
-            if (!mInjector.isRuntimeRestarted() && !mInjector.isFirstBoot()) {
+            // Do not report secondary users, runtime restarts or first boot/upgrade
+            if (userId == UserHandle.USER_SYSTEM
+                    && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
                 int uptimeSeconds = (int) (SystemClock.elapsedRealtime() / 1000);
                 MetricsLogger.histogram(mInjector.getContext(), "framework_boot_completed",
                         uptimeSeconds);
@@ -1703,8 +1715,13 @@
             return mService.mSystemServiceManager.isRuntimeRestarted();
         }
 
-        boolean isFirstBoot() {
-            return mService.mSystemServiceManager.isFirstBoot();
+        boolean isFirstBootOrUpgrade() {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            try {
+                return pm.isFirstBoot() || pm.isUpgrade();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
 
         void sendPreBootBroadcast(int userId, boolean quiet, final Runnable onFinish) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bd319b9..49423b9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -144,7 +144,8 @@
  */
 public class AudioService extends IAudioService.Stub
         implements AccessibilityManager.TouchExplorationStateChangeListener,
-            AccessibilityManager.AccessibilityStateChangeListener{
+            AccessibilityManager.AccessibilityStateChangeListener,
+            AccessibilityManager.AccessibilityServicesStateChangeListener {
 
     private static final String TAG = "AudioService";
 
@@ -780,7 +781,7 @@
                 TAG,
                 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
 
-        initA11yMonitoring(mContext);
+        initA11yMonitoring();
         onIndicateSystemReady();
     }
 
@@ -5925,13 +5926,25 @@
     //==========================================================================================
     // Accessibility
 
-    private void initA11yMonitoring(Context ctxt) {
-        AccessibilityManager accessibilityManager =
-                (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
+    /**
+     * Compile-time constant to enable the use of an independent a11y volume:
+     * - set to true to listen to a11y services state changes and read
+     *   the whether any exposes the FLAG_ENABLE_ACCESSIBILITY_VOLUME flag
+     * - set to false to listen to when accessibility services are started (e.g. "TalkBack started")
+     */
+    private static final boolean USE_FLAG_ENABLE_ACCESSIBILITY_VOLUME = true;
+
+    private void initA11yMonitoring() {
+        final AccessibilityManager accessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
         updateA11yVolumeAlias(accessibilityManager.isEnabled());
         accessibilityManager.addTouchExplorationStateChangeListener(this);
-        accessibilityManager.addAccessibilityStateChangeListener(this);
+        if (USE_FLAG_ENABLE_ACCESSIBILITY_VOLUME) {
+            accessibilityManager.addAccessibilityServicesStateChangeListener(this);
+        } else {
+            accessibilityManager.addAccessibilityStateChangeListener(this);
+        }
     }
 
     //---------------------------------------------------------------------------------
@@ -5969,21 +5982,31 @@
 
     private static boolean sIndependentA11yVolume = false;
 
+    // implementation of AccessibilityStateChangeListener
     @Override
     public void onAccessibilityStateChanged(boolean enabled) {
         updateA11yVolumeAlias(enabled);
     }
 
-    private void updateA11yVolumeAlias(boolean a11Enabled) {
-        if (DEBUG_VOL) Log.d(TAG, "Accessibility mode changed to " + a11Enabled);
-        // a11y has its own volume stream when a11y service is enabled
-        sIndependentA11yVolume = a11Enabled;
-        // update the volume mapping scheme
-        updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
-        // update the volume controller behavior
-        mVolumeController.setA11yMode(sIndependentA11yVolume ?
-                VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
-                    VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+    // implementation of AccessibilityServicesStateChangeListener
+    @Override
+    public void onAccessibilityServicesStateChanged() {
+        final AccessibilityManager accessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
+    }
+
+    private void updateA11yVolumeAlias(boolean a11VolEnabled) {
+        if (DEBUG_VOL) Log.d(TAG, "Accessibility volume enabled = " + a11VolEnabled);
+        if (sIndependentA11yVolume != a11VolEnabled) {
+            sIndependentA11yVolume = a11VolEnabled;
+            // update the volume mapping scheme
+            updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
+            // update the volume controller behavior
+            mVolumeController.setA11yMode(sIndependentA11yVolume ?
+                    VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
+                        VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+        }
     }
 
     //==========================================================================================
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5f9efe7..85d1d1e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -23,6 +23,7 @@
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
+import android.net.TrafficStats;
 import android.os.SystemClock;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -381,7 +382,12 @@
         protected void setupSocket(
                 int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
                 throws ErrnoException, IOException {
-            mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+            try {
+                mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
+            } finally {
+                TrafficStats.setThreadStatsTag(oldTag);
+            }
             // Setting SNDTIMEO is purely for defensive purposes.
             Os.setsockoptTimeval(mFileDescriptor,
                     SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(writeTimeout));
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index c40780e..fbda901 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -779,6 +779,7 @@
         int httpResponseCode = 599;
         String redirectUrl = null;
         final Stopwatch probeTimer = new Stopwatch().start();
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
         try {
             urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url);
             urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
@@ -839,6 +840,7 @@
             if (urlConnection != null) {
                 urlConnection.disconnect();
             }
+            TrafficStats.setThreadStatsTag(oldTag);
         }
         logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
         return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 58c76ec..34826b6 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -25,6 +25,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.net.ProxyInfo;
+import android.net.TrafficStats;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -103,11 +104,15 @@
             String file;
             synchronized (mProxyLock) {
                 if (Uri.EMPTY.equals(mPacUrl)) return;
+                final int oldTag = TrafficStats
+                        .getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC);
                 try {
                     file = get(mPacUrl);
                 } catch (IOException ioe) {
                     file = null;
                     Log.w(TAG, "Failed to load PAC file: " + ioe);
+                } finally {
+                    TrafficStats.setThreadStatsTag(oldTag);
                 }
             }
             if (file != null) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 0c80166..e84bf40 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -16,6 +16,11 @@
 
 package com.android.server.connectivity;
 
+import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -71,6 +76,7 @@
 import com.android.server.connectivity.tethering.IControlsTethering;
 import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
 import com.android.server.connectivity.tethering.IPv6TetheringInterfaceServices;
+import com.android.server.connectivity.tethering.TetheringConfiguration;
 import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
 import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
 import com.android.server.net.BaseNetworkObserver;
@@ -108,23 +114,11 @@
     private static final SparseArray<String> sMagicDecoderRing =
             MessageUtils.findMessageNames(messageClasses);
 
-    // TODO - remove both of these - should be part of interface inspection/selection stuff
-    private String[] mTetherableUsbRegexs;
-    private String[] mTetherableWifiRegexs;
-    private String[] mTetherableBluetoothRegexs;
-    private Collection<Integer> mUpstreamIfaceTypes;
+    private volatile TetheringConfiguration mConfig;
 
     // used to synchronize public access to members
     private final Object mPublicSync;
 
-    private static final Integer MOBILE_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE);
-    private static final Integer HIPRI_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_HIPRI);
-    private static final Integer DUN_TYPE = new Integer(ConnectivityManager.TYPE_MOBILE_DUN);
-
-    // if we have to connect to mobile, what APN type should we use?  Calculated by examining the
-    // upstream type list and the DUN_REQUIRED secure-setting
-    private int mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_NONE;
-
     private final INetworkManagementService mNMService;
     private final INetworkStatsService mStatsService;
     private final INetworkPolicyManager mPolicyManager;
@@ -150,24 +144,6 @@
     private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
             .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
 
-    // USB is  192.168.42.1 and 255.255.255.0
-    // Wifi is 192.168.43.1 and 255.255.255.0
-    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
-    // with 255.255.255.0
-    // P2P is 192.168.49.1 and 255.255.255.0
-
-    private String[] mDhcpRange;
-    private static final String[] DHCP_DEFAULT_RANGE = {
-        "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
-        "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
-        "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
-        "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
-    };
-
-    private String[] mDefaultDnsServers;
-    private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
-    private static final String DNS_DEFAULT_SERVER2 = "8.8.4.4";
-
     private final StateMachine mTetherMasterSM;
     private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
     private String mCurrentUpstreamIface;
@@ -208,27 +184,16 @@
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        mContext.registerReceiver(mStateReceiver, filter);
+        mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
 
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_MEDIA_SHARED);
         filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
         filter.addDataScheme("file");
-        mContext.registerReceiver(mStateReceiver, filter);
-
-        mDhcpRange = context.getResources().getStringArray(
-                com.android.internal.R.array.config_tether_dhcp_range);
-        if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
-            mDhcpRange = DHCP_DEFAULT_RANGE;
-        }
+        mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler());
 
         // load device config info
         updateConfiguration();
-
-        // TODO - remove and rely on real notifications of the current iface
-        mDefaultDnsServers = new String[2];
-        mDefaultDnsServers[0] = DNS_DEFAULT_SERVER1;
-        mDefaultDnsServers[1] = DNS_DEFAULT_SERVER2;
     }
 
     // We can't do this once in the Tethering() constructor and cache the value, because the
@@ -237,30 +202,8 @@
         return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
-    void updateConfiguration() {
-        String[] tetherableUsbRegexs = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_tether_usb_regexs);
-        String[] tetherableWifiRegexs = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_tether_wifi_regexs);
-        String[] tetherableBluetoothRegexs = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_tether_bluetooth_regexs);
-
-        int ifaceTypes[] = mContext.getResources().getIntArray(
-                com.android.internal.R.array.config_tether_upstream_types);
-        Collection<Integer> upstreamIfaceTypes = new ArrayList<>();
-        for (int i : ifaceTypes) {
-            upstreamIfaceTypes.add(new Integer(i));
-        }
-
-        synchronized (mPublicSync) {
-            mTetherableUsbRegexs = tetherableUsbRegexs;
-            mTetherableWifiRegexs = tetherableWifiRegexs;
-            mTetherableBluetoothRegexs = tetherableBluetoothRegexs;
-            mUpstreamIfaceTypes = upstreamIfaceTypes;
-        }
-
-        // check if the upstream type list needs to be modified due to secure-settings
-        checkDunRequired();
+    private void updateConfiguration() {
+        mConfig = new TetheringConfiguration(mContext);
     }
 
     @Override
@@ -300,39 +243,14 @@
         interfaceStatusChanged(iface, up);
     }
 
-    private boolean isUsb(String iface) {
-        synchronized (mPublicSync) {
-            for (String regex : mTetherableUsbRegexs) {
-                if (iface.matches(regex)) return true;
-            }
-            return false;
-        }
-    }
-
-    private boolean isWifi(String iface) {
-        synchronized (mPublicSync) {
-            for (String regex : mTetherableWifiRegexs) {
-                if (iface.matches(regex)) return true;
-            }
-            return false;
-        }
-    }
-
-    private boolean isBluetooth(String iface) {
-        synchronized (mPublicSync) {
-            for (String regex : mTetherableBluetoothRegexs) {
-                if (iface.matches(regex)) return true;
-            }
-            return false;
-        }
-    }
-
     private int ifaceNameToType(String iface) {
-        if (isWifi(iface)) {
+        final TetheringConfiguration cfg = mConfig;
+
+        if (cfg.isWifi(iface)) {
             return ConnectivityManager.TETHERING_WIFI;
-        } else if (isUsb(iface)) {
+        } else if (cfg.isUsb(iface)) {
             return ConnectivityManager.TETHERING_USB;
-        } else if (isBluetooth(iface)) {
+        } else if (cfg.isBluetooth(iface)) {
             return ConnectivityManager.TETHERING_BLUETOOTH;
         }
         return ConnectivityManager.TETHERING_INVALID;
@@ -662,6 +580,8 @@
         boolean usbTethered = false;
         boolean bluetoothTethered = false;
 
+        final TetheringConfiguration cfg = mConfig;
+
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
@@ -671,11 +591,11 @@
                 } else if (tetherState.mLastState == IControlsTethering.STATE_AVAILABLE) {
                     availableList.add(iface);
                 } else if (tetherState.mLastState == IControlsTethering.STATE_TETHERED) {
-                    if (isUsb(iface)) {
+                    if (cfg.isUsb(iface)) {
                         usbTethered = true;
-                    } else if (isWifi(iface)) {
+                    } else if (cfg.isWifi(iface)) {
                         wifiTethered = true;
-                    } else if (isBluetooth(iface)) {
+                    } else if (cfg.isBluetooth(iface)) {
                         bluetoothTethered = true;
                     }
                     activeList.add(iface);
@@ -779,69 +699,84 @@
     private class StateReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context content, Intent intent) {
-            String action = intent.getAction();
-            if (action == null) { return; }
+            final String action = intent.getAction();
+            if (action == null) return;
+
             if (action.equals(UsbManager.ACTION_USB_STATE)) {
-                synchronized (Tethering.this.mPublicSync) {
-                    boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
-                    mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false);
-                    // start tethering if we have a request pending
-                    if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
-                        tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB);
-                    }
-                    mUsbTetherRequested = false;
-                }
+                handleUsbAction(intent);
             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
-                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
-                        ConnectivityManager.EXTRA_NETWORK_INFO);
-                if (networkInfo != null &&
-                        networkInfo.getDetailedState() != NetworkInfo.DetailedState.FAILED) {
-                    if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION");
-                    mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
-                }
+                handleConnectivityAction(intent);
             } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
-                synchronized (Tethering.this.mPublicSync) {
-                    int curState =  intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
-                            WifiManager.WIFI_AP_STATE_DISABLED);
-                    switch (curState) {
-                        case WifiManager.WIFI_AP_STATE_ENABLING:
-                            // We can see this state on the way to both enabled and failure states.
-                            break;
-                        case WifiManager.WIFI_AP_STATE_ENABLED:
-                            // When the AP comes up and we've been requested to tether it, do so.
-                            if (mWifiTetherRequested) {
-                                tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
-                            }
-                            break;
-                        case WifiManager.WIFI_AP_STATE_DISABLED:
-                        case WifiManager.WIFI_AP_STATE_DISABLING:
-                        case WifiManager.WIFI_AP_STATE_FAILED:
-                        default:
-                            if (DBG) {
-                                Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" +
-                                    curState);
-                            }
-                            // Tell appropriate interface state machines that they should tear
-                            // themselves down.
-                            for (int i = 0; i < mTetherStates.size(); i++) {
-                                TetherInterfaceStateMachine tism =
-                                        mTetherStates.valueAt(i).mStateMachine;
-                                if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
-                                    tism.sendMessage(
-                                            TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-                                    break;  // There should be at most one of these.
-                                }
-                            }
-                            // Regardless of whether we requested this transition, the AP has gone
-                            // down.  Don't try to tether again unless we're requested to do so.
-                            mWifiTetherRequested = false;
-                            break;
-                    }
-                }
+                handleWifiApAction(intent);
             } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                 updateConfiguration();
             }
         }
+
+        private void handleConnectivityAction(Intent intent) {
+            final NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
+                    ConnectivityManager.EXTRA_NETWORK_INFO);
+            if (networkInfo == null ||
+                    networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
+                return;
+            }
+
+            if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
+            mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+        }
+
+        private void handleUsbAction(Intent intent) {
+            final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
+            final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
+            synchronized (Tethering.this.mPublicSync) {
+                mRndisEnabled = rndisEnabled;
+                // start tethering if we have a request pending
+                if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
+                    tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_USB);
+                }
+                mUsbTetherRequested = false;
+            }
+        }
+
+        private void handleWifiApAction(Intent intent) {
+            final int curState =  intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
+            synchronized (Tethering.this.mPublicSync) {
+                switch (curState) {
+                    case WifiManager.WIFI_AP_STATE_ENABLING:
+                        // We can see this state on the way to both enabled and failure states.
+                        break;
+                    case WifiManager.WIFI_AP_STATE_ENABLED:
+                        // When the AP comes up and we've been requested to tether it, do so.
+                        if (mWifiTetherRequested) {
+                            tetherMatchingInterfaces(true, ConnectivityManager.TETHERING_WIFI);
+                        }
+                        break;
+                    case WifiManager.WIFI_AP_STATE_DISABLED:
+                    case WifiManager.WIFI_AP_STATE_DISABLING:
+                    case WifiManager.WIFI_AP_STATE_FAILED:
+                    default:
+                        if (DBG) {
+                            Log.d(TAG, "Canceling WiFi tethering request - AP_STATE=" +
+                                curState);
+                        }
+                        // Tell appropriate interface state machines that they should tear
+                        // themselves down.
+                        for (int i = 0; i < mTetherStates.size(); i++) {
+                            TetherInterfaceStateMachine tism =
+                                    mTetherStates.valueAt(i).mStateMachine;
+                            if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+                                tism.sendMessage(
+                                        TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+                                break;  // There should be at most one of these.
+                            }
+                        }
+                        // Regardless of whether we requested this transition, the AP has gone
+                        // down.  Don't try to tether again unless we're requested to do so.
+                        mWifiTetherRequested = false;
+                    break;
+                }
+            }
+        }
     }
 
     private void tetherMatchingInterfaces(boolean enable, int interfaceType) {
@@ -875,26 +810,38 @@
         }
     }
 
-    // TODO - return copies so people can't tamper
+    public TetheringConfiguration getTetheringConfiguration() {
+        return mConfig;
+    }
+
+    public boolean hasTetherableConfiguration() {
+        final TetheringConfiguration cfg = mConfig;
+        final boolean hasDownstreamConfiguration =
+                (cfg.tetherableUsbRegexs.length != 0) ||
+                (cfg.tetherableWifiRegexs.length != 0) ||
+                (cfg.tetherableBluetoothRegexs.length != 0);
+        final boolean hasUpstreamConfiguration = !cfg.preferredUpstreamIfaceTypes.isEmpty();
+
+        return hasDownstreamConfiguration && hasUpstreamConfiguration;
+    }
+
+    // TODO - update callers to use getTetheringConfiguration(),
+    // which has only final members.
     public String[] getTetherableUsbRegexs() {
-        return mTetherableUsbRegexs;
+        return copy(mConfig.tetherableUsbRegexs);
     }
 
     public String[] getTetherableWifiRegexs() {
-        return mTetherableWifiRegexs;
+        return copy(mConfig.tetherableWifiRegexs);
     }
 
     public String[] getTetherableBluetoothRegexs() {
-        return mTetherableBluetoothRegexs;
+        return copy(mConfig.tetherableBluetoothRegexs);
     }
 
     public int setUsbTethering(boolean enable) {
         if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
         UsbManager usbManager = mContext.getSystemService(UsbManager.class);
-        if (usbManager == null) {
-            return enable ? ConnectivityManager.TETHER_ERROR_MASTER_ERROR
-                          : ConnectivityManager.TETHER_ERROR_NO_ERROR;
-        }
 
         synchronized (mPublicSync) {
             if (enable) {
@@ -925,61 +872,6 @@
         return ConnectivityManager.TETHER_ERROR_NO_ERROR;
     }
 
-    public int[] getUpstreamIfaceTypes() {
-        int values[];
-        synchronized (mPublicSync) {
-            updateConfiguration();  // TODO - remove?
-            values = new int[mUpstreamIfaceTypes.size()];
-            Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator();
-            for (int i=0; i < mUpstreamIfaceTypes.size(); i++) {
-                values[i] = iterator.next();
-            }
-        }
-        return values;
-    }
-
-    private void checkDunRequired() {
-        int secureSetting = 2;
-        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
-        if (tm != null) {
-            secureSetting = tm.getTetherApnRequired();
-        }
-        synchronized (mPublicSync) {
-            // 2 = not set, 0 = DUN not required, 1 = DUN required
-            if (secureSetting != 2) {
-                int requiredApn = (secureSetting == 1 ?
-                        ConnectivityManager.TYPE_MOBILE_DUN :
-                        ConnectivityManager.TYPE_MOBILE_HIPRI);
-                if (requiredApn == ConnectivityManager.TYPE_MOBILE_DUN) {
-                    while (mUpstreamIfaceTypes.contains(MOBILE_TYPE)) {
-                        mUpstreamIfaceTypes.remove(MOBILE_TYPE);
-                    }
-                    while (mUpstreamIfaceTypes.contains(HIPRI_TYPE)) {
-                        mUpstreamIfaceTypes.remove(HIPRI_TYPE);
-                    }
-                    if (mUpstreamIfaceTypes.contains(DUN_TYPE) == false) {
-                        mUpstreamIfaceTypes.add(DUN_TYPE);
-                    }
-                } else {
-                    while (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
-                        mUpstreamIfaceTypes.remove(DUN_TYPE);
-                    }
-                    if (mUpstreamIfaceTypes.contains(MOBILE_TYPE) == false) {
-                        mUpstreamIfaceTypes.add(MOBILE_TYPE);
-                    }
-                    if (mUpstreamIfaceTypes.contains(HIPRI_TYPE) == false) {
-                        mUpstreamIfaceTypes.add(HIPRI_TYPE);
-                    }
-                }
-            }
-            if (mUpstreamIfaceTypes.contains(DUN_TYPE)) {
-                mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_DUN;
-            } else {
-                mPreferredUpstreamMobileApn = ConnectivityManager.TYPE_MOBILE_HIPRI;
-            }
-        }
-    }
-
     // TODO review API - maybe return ArrayList<String> here and below?
     public String[] getTetheredIfaces() {
         ArrayList<String> list = new ArrayList<String>();
@@ -1008,7 +900,7 @@
     }
 
     public String[] getTetheredDhcpRanges() {
-        return mDhcpRange;
+        return mConfig.dhcpRanges;
     }
 
     public String[] getErroredIfaces() {
@@ -1083,7 +975,7 @@
         private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
         private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
 
-        private int mPreviousMobileApn = ConnectivityManager.TYPE_NONE;
+        private int mPreviousMobileType = ConnectivityManager.TYPE_NONE;
 
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
 
@@ -1118,13 +1010,13 @@
                 return false;
             }
 
-            protected boolean turnOnUpstreamMobileConnection(int apnType) {
+            protected boolean requestUpstreamMobileConnection(int apnType) {
                 if (apnType == ConnectivityManager.TYPE_NONE) { return false; }
 
-                if (apnType != mPreviousMobileApn) {
+                if (apnType != mPreviousMobileType) {
                     // Unregister any previous mobile upstream callback because
                     // this request, if any, will be different.
-                    turnOffUpstreamMobileConnection();
+                    unrequestUpstreamMobileConnection();
                 }
 
                 if (mUpstreamNetworkMonitor.mobileNetworkRequested()) {
@@ -1136,28 +1028,29 @@
                     case ConnectivityManager.TYPE_MOBILE_DUN:
                     case ConnectivityManager.TYPE_MOBILE:
                     case ConnectivityManager.TYPE_MOBILE_HIPRI:
-                        mPreviousMobileApn = apnType;
+                        mPreviousMobileType = apnType;
                         break;
                     default:
                         return false;
                 }
 
-                // TODO: This should be called by the code that observes
-                // configuration changes, once the above code in this function
-                // is simplified (i.e. eradicated).
-                mUpstreamNetworkMonitor.mobileUpstreamRequiresDun(
+                // TODO: Replace this with a call to pass the current tethering
+                // configuration to mUpstreamNetworkMonitor and let it handle
+                // choosing APN type accordingly.
+                mUpstreamNetworkMonitor.updateMobileRequiresDun(
                         apnType == ConnectivityManager.TYPE_MOBILE_DUN);
 
                 mUpstreamNetworkMonitor.registerMobileNetworkRequest();
                 return true;
             }
 
-            protected void turnOffUpstreamMobileConnection() {
+            protected void unrequestUpstreamMobileConnection() {
                 mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
-                mPreviousMobileApn = ConnectivityManager.TYPE_NONE;
+                mPreviousMobileType = ConnectivityManager.TYPE_NONE;
             }
 
             protected boolean turnOnMasterTetherSettings() {
+                final TetheringConfiguration cfg = mConfig;
                 try {
                     mNMService.setIpForwardingEnabled(true);
                 } catch (Exception e) {
@@ -1165,11 +1058,11 @@
                     return false;
                 }
                 try {
-                    mNMService.startTethering(mDhcpRange);
+                    mNMService.startTethering(cfg.dhcpRanges);
                 } catch (Exception e) {
                     try {
                         mNMService.stopTethering();
-                        mNMService.startTethering(mDhcpRange);
+                        mNMService.startTethering(cfg.dhcpRanges);
                     } catch (Exception ee) {
                         transitionTo(mStartTetheringErrorState);
                         return false;
@@ -1202,29 +1095,31 @@
 
                 updateConfiguration(); // TODO - remove?
 
-                synchronized (mPublicSync) {
-                    if (VDBG) {
-                        Log.d(TAG, "chooseUpstreamType has upstream iface types:");
-                        for (Integer netType : mUpstreamIfaceTypes) {
-                            Log.d(TAG, " " + netType);
-                        }
-                    }
-
-                    for (Integer netType : mUpstreamIfaceTypes) {
-                        NetworkInfo info = cm.getNetworkInfo(netType.intValue());
-                        // TODO: if the network is suspended we should consider
-                        // that to be the same as connected here.
-                        if ((info != null) && info.isConnected()) {
-                            upType = netType.intValue();
-                            break;
-                        }
+                final TetheringConfiguration cfg = mConfig;
+                if (VDBG) {
+                    Log.d(TAG, "chooseUpstreamType has upstream iface types:");
+                    for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
+                        Log.d(TAG, " " + netType);
                     }
                 }
 
+                for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
+                    NetworkInfo info = cm.getNetworkInfo(netType.intValue());
+                    // TODO: if the network is suspended we should consider
+                    // that to be the same as connected here.
+                    if ((info != null) && info.isConnected()) {
+                        upType = netType.intValue();
+                        break;
+                    }
+                }
+
+                final int preferredUpstreamMobileApn = cfg.isDunRequired
+                        ? ConnectivityManager.TYPE_MOBILE_DUN
+                        : ConnectivityManager.TYPE_MOBILE_HIPRI;
                 if (DBG) {
                     Log.d(TAG, "chooseUpstreamType(" + tryCell + "),"
                             + " preferredApn="
-                            + ConnectivityManager.getNetworkTypeName(mPreferredUpstreamMobileApn)
+                            + ConnectivityManager.getNetworkTypeName(preferredUpstreamMobileApn)
                             + ", got type="
                             + ConnectivityManager.getNetworkTypeName(upType));
                 }
@@ -1233,11 +1128,11 @@
                     case ConnectivityManager.TYPE_MOBILE_DUN:
                     case ConnectivityManager.TYPE_MOBILE_HIPRI:
                         // If we're on DUN, put our own grab on it.
-                        turnOnUpstreamMobileConnection(upType);
+                        requestUpstreamMobileConnection(upType);
                         break;
                     case ConnectivityManager.TYPE_NONE:
                         if (tryCell &&
-                                turnOnUpstreamMobileConnection(mPreferredUpstreamMobileApn)) {
+                                requestUpstreamMobileConnection(preferredUpstreamMobileApn)) {
                             // We think mobile should be coming up; don't set a retry.
                         } else {
                             sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
@@ -1250,7 +1145,7 @@
                          * If we found NONE we don't want to do this as we want any previous
                          * requests to keep trying to bring up something we can use.
                          */
-                        turnOffUpstreamMobileConnection();
+                        unrequestUpstreamMobileConnection();
                         break;
                 }
 
@@ -1295,7 +1190,8 @@
             }
 
             protected void setDnsForwarders(final Network network, final LinkProperties lp) {
-                String[] dnsServers = mDefaultDnsServers;
+                // TODO: Set v4 and/or v6 DNS per available connectivity.
+                String[] dnsServers = mConfig.defaultIPv4DNS;
                 final Collection<InetAddress> dnses = lp.getDnsServers();
                 // TODO: Properly support the absence of DNS servers.
                 if (dnses != null && !dnses.isEmpty()) {
@@ -1330,96 +1226,127 @@
             }
         }
 
-        private final AtomicInteger mSimBcastGenerationNumber = new AtomicInteger(0);
-        private SimChangeBroadcastReceiver mBroadcastReceiver = null;
+        private class SimChangeListener {
+            private final Context mContext;
+            private final AtomicInteger mSimBcastGenerationNumber;
+            private BroadcastReceiver mBroadcastReceiver;
 
-        private void startListeningForSimChanges() {
-            if (DBG) Log.d(TAG, "startListeningForSimChanges");
-            if (mBroadcastReceiver == null) {
+            SimChangeListener(Context ctx) {
+                mContext = ctx;
+                mSimBcastGenerationNumber = new AtomicInteger(0);
+            }
+
+            public int generationNumber() {
+                return mSimBcastGenerationNumber.get();
+            }
+
+            public void startListening() {
+                if (DBG) Log.d(TAG, "startListening for SIM changes");
+
+                if (mBroadcastReceiver != null) return;
+
                 mBroadcastReceiver = new SimChangeBroadcastReceiver(
                         mSimBcastGenerationNumber.incrementAndGet());
                 final IntentFilter filter = new IntentFilter();
                 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
 
-                mContext.registerReceiver(mBroadcastReceiver, filter);
+                mContext.registerReceiver(mBroadcastReceiver, filter, null,
+                        mTetherMasterSM.getHandler());
             }
-        }
 
-        private void stopListeningForSimChanges() {
-            if (DBG) Log.d(TAG, "stopListeningForSimChanges");
-            if (mBroadcastReceiver != null) {
+            public void stopListening() {
+                if (DBG) Log.d(TAG, "stopListening for SIM changes");
+
+                if (mBroadcastReceiver == null) return;
+
                 mSimBcastGenerationNumber.incrementAndGet();
                 mContext.unregisterReceiver(mBroadcastReceiver);
                 mBroadcastReceiver = null;
             }
-        }
 
-        class SimChangeBroadcastReceiver extends BroadcastReceiver {
-            // used to verify this receiver is still current
-            final private int mGenerationNumber;
-
-            // we're interested in edge-triggered LOADED notifications, so
-            // ignore LOADED unless we saw an ABSENT state first
-            private boolean mSimAbsentSeen = false;
-
-            public SimChangeBroadcastReceiver(int generationNumber) {
-                super();
-                mGenerationNumber = generationNumber;
+            public boolean hasMobileHotspotProvisionApp() {
+                try {
+                    if (!mContext.getResources().getString(com.android.internal.R.string.
+                            config_mobile_hotspot_provision_app_no_ui).isEmpty()) {
+                        Log.d(TAG, "re-evaluate provisioning");
+                        return true;
+                    }
+                } catch (Resources.NotFoundException e) {}
+                Log.d(TAG, "no prov-check needed for new SIM");
+                return false;
             }
 
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (DBG) {
-                    Log.d(TAG, "simchange mGenerationNumber=" + mGenerationNumber +
-                            ", current generationNumber=" + mSimBcastGenerationNumber.get());
-                }
-                if (mGenerationNumber != mSimBcastGenerationNumber.get()) return;
+            private boolean isSimCardAbsent(String state) {
+                return IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state);
+            }
 
-                final String state =
-                        intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+            private boolean isSimCardLoaded(String state) {
+                return IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state);
+            }
 
-                Log.d(TAG, "got Sim changed to state " + state + ", mSimAbsentSeen=" +
-                        mSimAbsentSeen);
-                if (!mSimAbsentSeen && IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
-                    mSimAbsentSeen = true;
+            private void startProvisionIntent(int tetherType) {
+                final Intent startProvIntent = new Intent();
+                startProvIntent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
+                startProvIntent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
+                startProvIntent.setComponent(TETHER_SERVICE);
+                mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
+            }
+
+            private class SimChangeBroadcastReceiver extends BroadcastReceiver {
+                // used to verify this receiver is still current
+                final private int mGenerationNumber;
+
+                // we're interested in edge-triggered LOADED notifications, so
+                // ignore LOADED unless we saw an ABSENT state first
+                private boolean mSimAbsentSeen = false;
+
+                public SimChangeBroadcastReceiver(int generationNumber) {
+                    mGenerationNumber = generationNumber;
                 }
 
-                if (mSimAbsentSeen && IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
-                    mSimAbsentSeen = false;
-                    try {
-                        if (mContext.getResources().getString(com.android.internal.R.string.
-                                config_mobile_hotspot_provision_app_no_ui).isEmpty() == false) {
-                            ArrayList<Integer> tethered = new ArrayList<Integer>();
-                            synchronized (mPublicSync) {
-                                for (int i = 0; i < mTetherStates.size(); i++) {
-                                    TetherState tetherState = mTetherStates.valueAt(i);
-                                    if (tetherState.mLastState !=
-                                            IControlsTethering.STATE_TETHERED) {
-                                        continue;  // Skip interfaces that aren't tethered.
-                                    }
-                                    String iface = mTetherStates.keyAt(i);
-                                    int interfaceType = ifaceNameToType(iface);
-                                    if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
-                                        tethered.add(new Integer(interfaceType));
-                                    }
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final int currentGenerationNumber = mSimBcastGenerationNumber.get();
+
+                    if (DBG) {
+                        Log.d(TAG, "simchange mGenerationNumber=" + mGenerationNumber +
+                                ", current generationNumber=" + currentGenerationNumber);
+                    }
+                    if (mGenerationNumber != currentGenerationNumber) return;
+
+                    final String state = intent.getStringExtra(
+                            IccCardConstants.INTENT_KEY_ICC_STATE);
+                    Log.d(TAG, "got Sim changed to state " + state + ", mSimAbsentSeen=" +
+                            mSimAbsentSeen);
+
+                    if (isSimCardAbsent(state)) {
+                        if (!mSimAbsentSeen) mSimAbsentSeen = true;
+                        return;
+                    }
+
+                    if (isSimCardLoaded(state) && mSimAbsentSeen) {
+                        mSimAbsentSeen = false;
+
+                        if (!hasMobileHotspotProvisionApp()) return;
+
+                        ArrayList<Integer> tethered = new ArrayList<Integer>();
+                        synchronized (mPublicSync) {
+                            for (int i = 0; i < mTetherStates.size(); i++) {
+                                TetherState tetherState = mTetherStates.valueAt(i);
+                                if (tetherState.mLastState != IControlsTethering.STATE_TETHERED) {
+                                    continue;  // Skip interfaces that aren't tethered.
+                                }
+                                String iface = mTetherStates.keyAt(i);
+                                int interfaceType = ifaceNameToType(iface);
+                                if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
+                                    tethered.add(new Integer(interfaceType));
                                 }
                             }
-                            for (int tetherType : tethered) {
-                                Intent startProvIntent = new Intent();
-                                startProvIntent.putExtra(
-                                        ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
-                                startProvIntent.putExtra(
-                                        ConnectivityManager.EXTRA_RUN_PROVISION, true);
-                                startProvIntent.setComponent(TETHER_SERVICE);
-                                mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
-                            }
-                            Log.d(TAG, "re-evaluate provisioning");
-                        } else {
-                            Log.d(TAG, "no prov-check needed for new SIM");
                         }
-                    } catch (Resources.NotFoundException e) {
-                        Log.d(TAG, "no prov-check needed for new SIM");
-                        // not defined, do nothing
+
+                        for (int tetherType : tethered) {
+                            startProvisionIntent(tetherType);
+                        }
                     }
                 }
             }
@@ -1455,12 +1382,13 @@
         }
 
         class TetherModeAliveState extends TetherMasterUtilState {
+            final SimChangeListener simChange = new SimChangeListener(mContext);
             boolean mTryCell = true;
             @Override
             public void enter() {
                 // TODO: examine if we should check the return value.
                 turnOnMasterTetherSettings(); // may transition us out
-                startListeningForSimChanges();
+                simChange.startListening();
                 mUpstreamNetworkMonitor.start();
 
                 mTryCell = true;  // better try something first pass or crazy tests cases will fail
@@ -1470,9 +1398,9 @@
 
             @Override
             public void exit() {
-                turnOffUpstreamMobileConnection();
+                unrequestUpstreamMobileConnection();
                 mUpstreamNetworkMonitor.stop();
-                stopListeningForSimChanges();
+                simChange.stopListening();
                 notifyTetheredOfNewUpstreamIface(null);
                 handleNewUpstreamNetworkState(null);
             }
@@ -1672,9 +1600,10 @@
 
         pw.println("Tethering:");
         pw.increaseIndent();
-        pw.print("mUpstreamIfaceTypes:");
+        final TetheringConfiguration cfg = mConfig;
+        pw.print("preferredUpstreamIfaceTypes:");
         synchronized (mPublicSync) {
-            for (Integer netType : mUpstreamIfaceTypes) {
+            for (Integer netType : cfg.preferredUpstreamIfaceTypes) {
                 pw.print(" " + ConnectivityManager.getNetworkTypeName(netType));
             }
             pw.println();
@@ -1754,4 +1683,8 @@
         mTetherStates.put(iface, tetherState);
         tetherState.mStateMachine.start();
     }
+
+    private static String[] copy(String[] strarray) {
+        return Arrays.copyOf(strarray, strarray.length);
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
new file mode 100644
index 0000000..14d06cc
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -0,0 +1,163 @@
+/*
+ * 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.connectivity.tethering;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+
+/**
+ * A utility class to encapsulate the various tethering configuration elements.
+ *
+ * This configuration data includes elements describing upstream properties
+ * (preferred and required types of upstream connectivity as well as default
+ * DNS servers to use if none are available) and downstream properties (such
+ * as regular expressions use to match suitable downstream interfaces and the
+ * DHCPv4 ranges to use).
+ *
+ * @hide
+ */
+public class TetheringConfiguration {
+    private static final String TAG = TetheringConfiguration.class.getSimpleName();
+
+    private static final int DUN_NOT_REQUIRED = 0;
+    private static final int DUN_REQUIRED = 1;
+    private static final int DUN_UNSPECIFIED = 2;
+
+    // USB is  192.168.42.1 and 255.255.255.0
+    // Wifi is 192.168.43.1 and 255.255.255.0
+    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
+    // with 255.255.255.0
+    // P2P is 192.168.49.1 and 255.255.255.0
+    private static final String[] DHCP_DEFAULT_RANGE = {
+        "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
+        "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
+        "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
+        "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
+    };
+
+    private final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
+
+    public final String[] tetherableUsbRegexs;
+    public final String[] tetherableWifiRegexs;
+    public final String[] tetherableBluetoothRegexs;
+    public final boolean isDunRequired;
+    public final Collection<Integer> preferredUpstreamIfaceTypes;
+    public final String[] dhcpRanges;
+    public final String[] defaultIPv4DNS;
+
+    public TetheringConfiguration(Context ctx) {
+        tetherableUsbRegexs = ctx.getResources().getStringArray(
+                com.android.internal.R.array.config_tether_usb_regexs);
+        tetherableWifiRegexs = ctx.getResources().getStringArray(
+                com.android.internal.R.array.config_tether_wifi_regexs);
+        tetherableBluetoothRegexs = ctx.getResources().getStringArray(
+                com.android.internal.R.array.config_tether_bluetooth_regexs);
+
+        isDunRequired = checkDunRequired(ctx);
+        preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, isDunRequired);
+
+        dhcpRanges = getDhcpRanges(ctx);
+        defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
+    }
+
+    public boolean isUsb(String iface) {
+        return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
+    }
+
+    public boolean isWifi(String iface) {
+        return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
+    }
+
+    public boolean isBluetooth(String iface) {
+        return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
+    }
+
+    private static boolean checkDunRequired(Context ctx) {
+        final TelephonyManager tm = ctx.getSystemService(TelephonyManager.class);
+        final int secureSetting =
+                (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
+        return (secureSetting == DUN_REQUIRED);
+    }
+
+    private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, boolean requiresDun) {
+        final int ifaceTypes[] = ctx.getResources().getIntArray(
+                com.android.internal.R.array.config_tether_upstream_types);
+        final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
+        for (int i : ifaceTypes) {
+            switch (i) {
+                case TYPE_MOBILE:
+                case TYPE_MOBILE_HIPRI:
+                    if (requiresDun) continue;
+                    break;
+                case TYPE_MOBILE_DUN:
+                    if (!requiresDun) continue;
+                    break;
+            }
+            upstreamIfaceTypes.add(i);
+        }
+
+        // Fix up upstream interface types for DUN or mobile. NOTE: independent
+        // of the value of |requiresDun|, cell data of one form or another is
+        // *always* an upstream, regardless of the upstream interface types
+        // specified by configuration resources.
+        if (requiresDun) {
+            if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
+                upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
+            }
+        } else {
+            if (!upstreamIfaceTypes.contains(TYPE_MOBILE)) {
+                upstreamIfaceTypes.add(TYPE_MOBILE);
+            }
+            if (!upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)) {
+                upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
+            }
+        }
+
+        return upstreamIfaceTypes;
+    }
+
+    private static boolean matchesDownstreamRegexs(String iface, String[] regexs) {
+        for (String regex : regexs) {
+            if (iface.matches(regex)) return true;
+        }
+        return false;
+    }
+
+    private static String[] getDhcpRanges(Context ctx) {
+        final String[] fromResource = ctx.getResources().getStringArray(
+                com.android.internal.R.array.config_tether_dhcp_range);
+        if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
+            return fromResource;
+        }
+        return copy(DHCP_DEFAULT_RANGE);
+    }
+
+    private static String[] copy(String[] strarray) {
+        return Arrays.copyOf(strarray, strarray.length);
+    }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 927dfd5..23481dc 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -16,6 +16,9 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -106,7 +109,7 @@
         mNetworkMap.clear();
     }
 
-    public void mobileUpstreamRequiresDun(boolean dunRequired) {
+    public void updateMobileRequiresDun(boolean dunRequired) {
         final boolean valueChanged = (mDunRequired != dunRequired);
         mDunRequired = dunRequired;
         if (valueChanged && mobileNetworkRequested()) {
@@ -120,7 +123,10 @@
     }
 
     public void registerMobileNetworkRequest() {
-        if (mMobileNetworkCallback != null) return;
+        if (mMobileNetworkCallback != null) {
+            Log.e(TAG, "registerMobileNetworkRequest() already registered");
+            return;
+        }
 
         final NetworkRequest.Builder builder = new NetworkRequest.Builder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
@@ -136,13 +142,16 @@
         // Therefore, to avoid duplicate notifications, we only register a no-op.
         mMobileNetworkCallback = new NetworkCallback();
 
-        // TODO: Change the timeout from 0 (no onUnavailable callback) to use some
-        // moderate callback time (once timeout callbacks are implemented). This might
-        // be useful for updating some UI. Additionally, we should definitely log a
-        // message to aid in any subsequent debugging
-        if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
+        // TODO: Change the timeout from 0 (no onUnavailable callback) to some
+        // moderate callback timeout. This might be useful for updating some UI.
+        // Additionally, we log a message to aid in any subsequent debugging.
+        Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
 
-        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback);
+        // The following use of the legacy type system cannot be removed until
+        // after upstream selection no longer finds networks by legacy type.
+        // See also b/34364553.
+        final int apnType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
+        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, apnType);
     }
 
     public void releaseMobileNetworkRequest() {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 11a3f11..5b539ff 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1019,8 +1019,7 @@
         final int owningUid = syncAdapterInfo.uid;
         final String owningPackage = syncAdapterInfo.componentName.getPackageName();
         try {
-            if (ActivityManager.getService().getAppStartMode(owningUid,
-                    owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
+            if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
                 Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
                         + syncAdapterInfo.componentName
                         + " -- package not allowed to start");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 9c762cc..cd07793 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -48,6 +48,7 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.text.TextUtils;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -230,6 +231,9 @@
     // intended for use inside of the requestGlobalDisplayStateInternal function.
     private final ArrayList<Runnable> mTempDisplayStateWorkQueue = new ArrayList<Runnable>();
 
+    // Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs.
+    private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
+
     public DisplayManagerService(Context context) {
         super(context);
         mContext = context;
@@ -394,7 +398,8 @@
             LogicalDisplay display = mLogicalDisplays.get(displayId);
             if (display != null) {
                 DisplayInfo info = display.getDisplayInfoLocked();
-                if (info.hasAccess(callingUid)) {
+                if (info.hasAccess(callingUid)
+                        || isUidPresentOnDisplayInternal(callingUid, displayId)) {
                     return info;
                 }
             }
@@ -937,6 +942,25 @@
         }
     }
 
+    // Updates the lists of UIDs that are present on displays.
+    private void setDisplayAccessUIDsInternal(SparseArray<IntArray> newDisplayAccessUIDs) {
+        synchronized (mSyncRoot) {
+            mDisplayAccessUIDs.clear();
+            for (int i = newDisplayAccessUIDs.size() - 1; i >= 0; i--) {
+                mDisplayAccessUIDs.append(newDisplayAccessUIDs.keyAt(i),
+                        newDisplayAccessUIDs.valueAt(i));
+            }
+        }
+    }
+
+    // Checks if provided UID's content is present on the display and UID has access to it.
+    private boolean isUidPresentOnDisplayInternal(int uid, int displayId) {
+        synchronized (mSyncRoot) {
+            final IntArray displayUIDs = mDisplayAccessUIDs.get(displayId);
+            return displayUIDs != null && displayUIDs.indexOf(uid) != -1;
+        }
+    }
+
     private void clearViewportsLocked() {
         mDefaultViewport.valid = false;
         mExternalTouchViewport.valid = false;
@@ -1647,5 +1671,15 @@
         public void setDisplayOffsets(int displayId, int x, int y) {
             setDisplayOffsetsInternal(displayId, x, y);
         }
+
+        @Override
+        public void setDisplayAccessUIDs(SparseArray<IntArray> newDisplayAccessUIDs) {
+            setDisplayAccessUIDsInternal(newDisplayAccessUIDs);
+        }
+
+        @Override
+        public boolean isUidPresentOnDisplay(int uid, int displayId) {
+            return isUidPresentOnDisplayInternal(uid, displayId);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 8673225..841a951 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -285,6 +285,7 @@
                 int activeColorMode) {
             List<Integer> pendingColorModes = new ArrayList<>();
 
+            if (colorModes == null) return false;
             // Build an updated list of all existing color modes.
             boolean colorModesAdded = false;
             for (int colorMode: colorModes) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 87f4030..fbb39384 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,6 +25,7 @@
 import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
@@ -1700,6 +1701,7 @@
     // Binder call
     @Override
     public void setCustomPointerIcon(PointerIcon icon) {
+        Preconditions.checkNotNull(icon);
         nativeSetCustomPointerIcon(mPtr, icon);
     }
 
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index f42c5be..a748013 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -566,8 +566,8 @@
             String tag) {
         JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
         try {
-            if (ActivityManager.getService().getAppStartMode(uId,
-                    job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
+            if (ActivityManager.getService().isAppStartModeDisabled(uId,
+                    job.getService().getPackageName())) {
                 Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()
                         + " -- package not allowed to start");
                 return JobScheduler.RESULT_FAILURE;
@@ -1201,9 +1201,8 @@
             public void process(JobStatus job) {
                 if (isReadyToBeExecutedLocked(job)) {
                     try {
-                        if (ActivityManager.getService().getAppStartMode(job.getUid(),
-                                job.getJob().getService().getPackageName())
-                                == ActivityManager.APP_START_MODE_DISABLED) {
+                        if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(),
+                                job.getJob().getService().getPackageName())) {
                             Slog.w(TAG, "Aborting job " + job.getUid() + ":"
                                     + job.getJob().toString() + " -- package not allowed to start");
                             mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget();
diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
index bf779859..62332c9 100644
--- a/services/core/java/com/android/server/location/GpsXtraDownloader.java
+++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java
@@ -16,22 +16,19 @@
 
 package com.android.server.location;
 
+import android.net.TrafficStats;
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
-
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
 import java.util.Properties;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
-import libcore.io.Streams;
-
 /**
  * A class for downloading GPS XTRA data.
  *
@@ -94,7 +91,12 @@
 
         // load balance our requests among the available servers
         while (result == null) {
-            result = doDownload(mXtraServers[mNextServerIndex]);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_GPS);
+            try {
+                result = doDownload(mXtraServers[mNextServerIndex]);
+            } finally {
+                TrafficStats.setThreadStatsTag(oldTag);
+            }
 
             // increment mNextServerIndex and wrap around if necessary
             mNextServerIndex++;
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index c48f430..ee00fdc 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -17,6 +17,8 @@
 package com.android.server.net;
 
 import android.net.NetworkIdentity;
+import android.service.NetworkIdentitySetProto;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -143,4 +145,14 @@
         final NetworkIdentity anotherIdent = another.iterator().next();
         return ident.compareTo(anotherIdent);
     }
+
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        for (NetworkIdentity ident : this) {
+            ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES);
+        }
+
+        proto.end(start);
+    }
 }
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index c45b416..0354300 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -34,9 +34,13 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.os.Binder;
+import android.service.NetworkStatsCollectionKeyProto;
+import android.service.NetworkStatsCollectionProto;
+import android.service.NetworkStatsCollectionStatsProto;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.IntArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FileRotator;
@@ -532,12 +536,15 @@
                 / mBucketDuration);
     }
 
-    public void dump(IndentingPrintWriter pw) {
+    private ArrayList<Key> getSortedKeys() {
         final ArrayList<Key> keys = Lists.newArrayList();
         keys.addAll(mStats.keySet());
         Collections.sort(keys);
+        return keys;
+    }
 
-        for (Key key : keys) {
+    public void dump(IndentingPrintWriter pw) {
+        for (Key key : getSortedKeys()) {
             pw.print("ident="); pw.print(key.ident.toString());
             pw.print(" uid="); pw.print(key.uid);
             pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
@@ -550,6 +557,29 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        for (Key key : getSortedKeys()) {
+            final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
+
+            // Key
+            final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
+            key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY);
+            proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
+            proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
+            proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
+            proto.end(startKey);
+
+            // Value
+            final NetworkStatsHistory history = mStats.get(key);
+            history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY);
+            proto.end(startStats);
+        }
+
+        proto.end(start);
+    }
+
     public void dumpCheckin(PrintWriter pw, long start, long end) {
         dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
         dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 090a076..80309e1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -29,9 +29,11 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.os.DropBoxManager;
+import android.service.NetworkStatsRecorderProto;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.net.VpnInfo;
 import com.android.internal.util.FileRotator;
@@ -465,6 +467,15 @@
         }
     }
 
+    public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+        if (mPending != null) {
+            proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
+        }
+        getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
+        proto.end(start);
+    }
+
     public void dumpCheckin(PrintWriter pw, long start, long end) {
         // Only load and dump stats from the requested window
         getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 386e78b..104c296 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -104,6 +104,8 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.NetworkInterfaceProto;
+import android.service.NetworkStatsServiceDumpProto;
 import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -115,6 +117,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.TrustedTime;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.VpnInfo;
@@ -1255,6 +1258,12 @@
         final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, "  ");
 
         synchronized (mStatsLock) {
+            if (args.length > 0 && "--proto".equals(args[0])) {
+                // In this case ignore all other arguments.
+                dumpProto(fd);
+                return;
+            }
+
             if (poll) {
                 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
                 pw.println("Forced poll");
@@ -1327,6 +1336,33 @@
         }
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        // TODO Right now it writes all history.  Should it limit to the "since-boot" log?
+
+        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces);
+        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces);
+        mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
+        mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
+        mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
+        mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
+
+        proto.flush();
+    }
+
+    private static void dumpInterfaces(ProtoOutputStream proto, long tag,
+            ArrayMap<String, NetworkIdentitySet> ifaces) {
+        for (int i = 0; i < ifaces.size(); i++) {
+            final long start = proto.start(tag);
+
+            proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
+            ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES);
+
+            proto.end(start);
+        }
+    }
+
     /**
      * Return snapshot of current UID statistics, including any
      * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f09e856..168884d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -198,6 +198,8 @@
 
     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
 
+    static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
+
     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
 
     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
@@ -229,6 +231,7 @@
 
     private IActivityManager mAm;
     private IPackageManager mPackageManager;
+    private PackageManager mPackageManagerClient;
     AudioManager mAudioManager;
     AudioManagerInternal mAudioManagerInternal;
     @Nullable StatusBarManagerInternal mStatusBar;
@@ -268,6 +271,7 @@
     private boolean mNotificationPulseEnabled;
 
     // used as a mutex for access to all active notifications & listeners
+    final Object mNotificationLock = new Object();
     final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
@@ -372,7 +376,7 @@
 
     private void loadPolicyFile() {
         if (DBG) Slog.d(TAG, "loadPolicyFile");
-        synchronized(mPolicyFile) {
+        synchronized (mPolicyFile) {
 
             FileInputStream infile = null;
             try {
@@ -491,7 +495,7 @@
 
         @Override
         public void onSetDisabled(int status) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 mDisableNotificationEffects =
                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
                 if (disableNotificationEffects(null) != null) {
@@ -519,7 +523,7 @@
 
         @Override
         public void onClearAll(int callingUid, int callingPid, int userId) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
                         /*includeCurrentProfiles*/ true);
             }
@@ -527,7 +531,7 @@
 
         @Override
         public void onNotificationClick(int callingUid, int callingPid, String key) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r == null) {
                     Log.w(TAG, "No notification with key: " + key);
@@ -548,7 +552,7 @@
         @Override
         public void onNotificationActionClick(int callingUid, int callingPid, String key,
                 int actionIndex) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r == null) {
                     Log.w(TAG, "No notification with key: " + key);
@@ -584,7 +588,7 @@
 
         @Override
         public void clearEffects() {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 if (DBG) Slog.d(TAG, "clearEffects");
                 clearSoundLocked();
                 clearVibrateLocked();
@@ -601,7 +605,7 @@
                     REASON_DELEGATE_ERROR, null);
             long ident = Binder.clearCallingIdentity();
             try {
-                ActivityManager.getService().crashApplication(uid, initialPid, pkg,
+                ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
                         "Bad notification posted from package " + pkg
                         + ": " + message);
             } catch (RemoteException e) {
@@ -612,7 +616,7 @@
         @Override
         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
                 NotificationVisibility[] noLongerVisibleKeys) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 for (NotificationVisibility nv : newlyVisibleKeys) {
                     NotificationRecord r = mNotificationsByKey.get(nv.key);
                     if (r == null) continue;
@@ -635,7 +639,7 @@
         @Override
         public void onNotificationExpansionChanged(String key,
                 boolean userAction, boolean expanded) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
                     r.stats.onExpansionChanged(userAction, expanded);
@@ -702,16 +706,19 @@
                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                         UserHandle.USER_ALL);
                 String pkgList[] = null;
+                int uidList[] = null;
                 boolean removingPackage = queryRemove &&
                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                    uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                     reason = REASON_PACKAGE_SUSPENDED;
                 } else if (queryRestart) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+                    uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
                 } else {
                     Uri uri = intent.getData();
                     if (uri == null) {
@@ -743,8 +750,8 @@
                         }
                     }
                     pkgList = new String[]{pkgName};
+                    uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
                 }
-
                 if (pkgList != null && (pkgList.length > 0)) {
                     for (String pkgName : pkgList) {
                         if (cancelNotifications) {
@@ -756,7 +763,8 @@
                 mListeners.onPackagesChanged(removingPackage, pkgList);
                 mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
                 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
-                mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList);
+                mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
+                savePolicyFile();
             }
         }
     };
@@ -945,7 +953,8 @@
 
     // TODO: Tests should call onStart instead once the methods above are removed.
     @VisibleForTesting
-    void init(IPackageManager packageManager, LightsManager lightsManager) {
+    void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
+            LightsManager lightsManager, NotificationListeners notificationListeners) {
         Resources resources = getContext().getResources();
         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -953,11 +962,12 @@
 
         mAm = ActivityManager.getService();
         mPackageManager = packageManager;
+        mPackageManagerClient = packageManagerClient;
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
 
-        mHandler = new WorkerHandler();
+        mHandler = new WorkerHandler(looper);
         mRankingThread.start();
         String[] extractorNames;
         try {
@@ -987,7 +997,7 @@
                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
-                synchronized(mNotificationList) {
+                synchronized (mNotificationLock) {
                     updateInterruptionFilterLocked();
                 }
             }
@@ -1015,7 +1025,7 @@
         mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
             @Override
             public void addAutoGroup(String key) {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     addAutogroupKeyLocked(key);
                 }
                 mRankingHandler.requestSort(false);
@@ -1023,7 +1033,7 @@
 
             @Override
             public void removeAutoGroup(String key) {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     removeAutogroupKeyLocked(key);
                 }
                 mRankingHandler.requestSort(false);
@@ -1036,7 +1046,7 @@
 
             @Override
             public void removeAutoGroupSummary(int userId, String pkg) {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     clearAutogroupSummaryLocked(userId, pkg);
                 }
             }
@@ -1047,8 +1057,8 @@
 
         syncBlockDb();
 
-        // This is a MangedServices object that keeps track of the listeners.
-        mListeners = new NotificationListeners();
+        // This is a ManagedServices object that keeps track of the listeners.
+        mListeners = notificationListeners;
 
         // This is a MangedServices object that keeps track of the assistant.
         mNotificationAssistants = new NotificationAssistants();
@@ -1130,7 +1140,8 @@
 
     @Override
     public void onStart() {
-        init(AppGlobals.getPackageManager(), getLocalService(LightsManager.class));
+        init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
+                getLocalService(LightsManager.class), new NotificationListeners());
         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
         publishLocalService(NotificationManagerInternal.class, mInternalService);
     }
@@ -1527,14 +1538,16 @@
         @Override
         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
             checkCallerIsSystemOrSameApp(pkg);
-            return mRankingHelper.getNotificationChannel(pkg, Binder.getCallingUid(), channelId);
+            return mRankingHelper.getNotificationChannel(
+                    pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
         }
 
         @Override
         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
-                String channelId) {
+                String channelId, boolean includeDeleted) {
             checkCallerIsSystem();
-            return mRankingHelper.getNotificationChannel(pkg, uid, channelId);
+            return mRankingHelper.getNotificationChannel
+                    (pkg, uid, channelId, includeDeleted);
         }
 
         @Override
@@ -1566,17 +1579,42 @@
 
         @Override
         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
-                int uid) {
+                int uid, boolean includeDeleted) {
             checkCallerIsSystem();
-            return mRankingHelper.getNotificationChannels(pkg, uid);
+            return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
         }
 
         @Override
         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
-            return mRankingHelper.getNotificationChannels(pkg, Binder.getCallingUid());
+            return mRankingHelper.getNotificationChannels(
+                    pkg, Binder.getCallingUid(), false /* includeDeleted */);
         }
 
+
+        @Override
+        public void clearData(String packageName, int uid) throws RemoteException {
+            checkCallerIsSystem();
+
+            // Cancel posted notifications
+            cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
+                    UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
+
+            // Listener & assistant
+            mListeners.onPackagesChanged(true, new String[] {packageName});
+            mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
+
+            // Zen
+            mConditionProviders.onPackagesChanged(true, new String[] {packageName});
+
+            // Reset notification preferences
+            mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
+                    new String[] {packageName}, new int[] {uid});
+
+            savePolicyFile();
+        }
+
+
         /**
          * System-only API for getting a list of current (i.e. not cleared) notifications.
          *
@@ -1596,7 +1634,7 @@
             // noteOp will check to make sure the callingPkg matches the uid
             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
                     == AppOpsManager.MODE_ALLOWED) {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     tmp = new StatusBarNotification[mNotificationList.size()];
                     final int N = mNotificationList.size();
                     for (int i=0; i<N; i++) {
@@ -1622,7 +1660,7 @@
             final ArrayMap<String, StatusBarNotification> map
                     = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
 
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 final int N = mNotificationList.size();
                 for (int i = 0; i < N; i++) {
                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
@@ -1637,10 +1675,8 @@
                         map.put(sbn.getKey(), sbn);
                     }
                 }
-            }
-            synchronized (mEnqueuedNotifications) {
-                final int N = mEnqueuedNotifications.size();
-                for (int i = 0; i < N; i++) {
+                final int M = mEnqueuedNotifications.size();
+                for (int i = 0; i < M; i++) {
                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
                             mEnqueuedNotifications.get(i).sbn);
                     if (sbn != null) {
@@ -1732,7 +1768,7 @@
             final int callingPid = Binder.getCallingPid();
             long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                     if (keys != null) {
                         final int N = keys.length;
@@ -1795,7 +1831,7 @@
         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
             long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                     if (keys != null) {
                         final int N = keys.length;
@@ -1850,7 +1886,7 @@
             long identity = Binder.clearCallingIdentity();
             try {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                snoozeNotificationInt(key, snoozeCriterionId, info);
+                snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -1867,7 +1903,7 @@
             long identity = Binder.clearCallingIdentity();
             try {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                snoozeNotificationInt(key, snoozeUntil, info);
+                snoozeNotificationInt(key, snoozeUntil, null, info);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -1883,7 +1919,7 @@
             long identity = Binder.clearCallingIdentity();
             try {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                snoozeNotificationInt(key, info);
+                snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, null, info);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -1919,7 +1955,7 @@
             final int callingPid = Binder.getCallingPid();
             long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                     if (info.supportsProfiles()) {
                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
@@ -1948,7 +1984,7 @@
         @Override
         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
                 INotificationListener token, String[] keys, int trim) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                 final boolean getKeys = keys != null;
                 final int N = getKeys ? keys.length : mNotificationList.size();
@@ -1973,7 +2009,7 @@
         public void requestHintsFromListener(INotificationListener token, int hints) {
             final long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
@@ -1994,7 +2030,7 @@
 
         @Override
         public int getHintsFromListener(INotificationListener token) {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 return mListenerHints;
             }
         }
@@ -2004,7 +2040,7 @@
                 int interruptionFilter) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
                     updateInterruptionFilterLocked();
@@ -2025,7 +2061,7 @@
         @Override
         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
                 throws RemoteException {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
                 if (info == null) return;
                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
@@ -2344,7 +2380,7 @@
             enforceSystemOrSystemUI("grant notification policy access");
             final long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     mPolicyAccess.put(pkg, granted);
                 }
             } finally {
@@ -2379,7 +2415,7 @@
                 Adjustment adjustment) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mEnqueuedNotifications) {
+                synchronized (mNotificationLock) {
                     mNotificationAssistants.checkServiceTokenLocked(token);
                     int N = mEnqueuedNotifications.size();
                     for (int i = 0; i < N; i++) {
@@ -2401,7 +2437,7 @@
                 Adjustment adjustment) throws RemoteException {
             final long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     mNotificationAssistants.checkServiceTokenLocked(token);
                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
                     applyAdjustment(n, adjustment);
@@ -2418,7 +2454,7 @@
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                synchronized (mNotificationList) {
+                synchronized (mNotificationLock) {
                     mNotificationAssistants.checkServiceTokenLocked(token);
                     for (Adjustment adjustment : adjustments) {
                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
@@ -2475,7 +2511,7 @@
                 INotificationListener token, String pkg) throws RemoteException {
             ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
             int uid = mPackageManager.getPackageUid(pkg, 0, info.userid);
-            return mRankingHelper.getNotificationChannels(pkg, uid);
+            return mRankingHelper.getNotificationChannels(pkg, uid, false /* includeDeleted */);
         }
     };
 
@@ -2493,7 +2529,8 @@
                     adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
             if (!TextUtils.isEmpty(overrideChannelId)) {
                 n.setNotificationChannelOverride(mRankingHelper.getNotificationChannel(
-                        n.sbn.getPackageName(), n.sbn.getUid(), overrideChannelId));
+                        n.sbn.getPackageName(), n.sbn.getUid(), overrideChannelId,
+                        false /* includeDeleted */));
             }
             n.setPeopleOverride(people);
             n.setSnoozeCriteria(snoozeCriterionList);
@@ -2523,9 +2560,8 @@
         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
         if (summaries != null && summaries.containsKey(pkg)) {
             // Clear summary.
-            final NotificationRecord removed = mNotificationsByKey.get(summaries.remove(pkg));
+            final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
             if (removed != null) {
-                mNotificationList.remove(removed);
                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
             }
         }
@@ -2534,7 +2570,7 @@
     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
         NotificationRecord summaryRecord = null;
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
             if (notificationRecord == null) {
                 // The notification could have been cancelled again already. A successive
@@ -2585,7 +2621,7 @@
             }
         }
         if (summaryRecord != null) {
-            synchronized (mEnqueuedNotifications) {
+            synchronized (mNotificationLock) {
                 mEnqueuedNotifications.add(summaryRecord);
             }
             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
@@ -2640,7 +2676,7 @@
             }
         }
 
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             if (!zenOnly) {
                 N = mNotificationList.size();
                 if (N > 0) {
@@ -2678,19 +2714,17 @@
                 }
                 pw.println("  mArchive=" + mArchive.toString());
                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
-                int i=0;
+                int j=0;
                 while (iter.hasNext()) {
                     final StatusBarNotification sbn = iter.next();
                     if (filter != null && !filter.matches(sbn)) continue;
                     pw.println("    " + sbn);
-                    if (++i >= 5) {
+                    if (++j >= 5) {
                         if (iter.hasNext()) pw.println("    ...");
                         break;
                     }
                 }
-            }
 
-            synchronized (mEnqueuedNotifications) {
                 if (!zenOnly) {
                     N = mEnqueuedNotifications.size();
                     if (N > 0) {
@@ -2785,14 +2819,14 @@
         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
                 int userId) {
             checkCallerIsSystem();
-            synchronized (mNotificationList) {
-                int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
-                if (i < 0) {
+            synchronized (mNotificationLock) {
+                NotificationRecord r = findNotificationByListLocked(mNotificationList, pkg, null,
+                        notificationId, userId);
+                if (r == null) {
                     Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
                             + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
                     return;
                 }
-                NotificationRecord r = mNotificationList.get(i);
                 StatusBarNotification sbn = r.sbn;
                 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
                 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
@@ -2829,7 +2863,7 @@
 
         // Fix the notification as best we can.
         try {
-            final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
+            final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
             Notification.addFieldsFromContext(ai, userId, notification);
@@ -2846,7 +2880,7 @@
                     + " id=" + id + " notification=" + notification);
         }
         final NotificationChannel channel =  mRankingHelper.getNotificationChannelWithFallback(pkg,
-                callingUid, notification.getChannel());
+                callingUid, notification.getChannel(), false /* includeDeleted */);
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, channel, id, tag, callingUid, callingPid, notification,
                 user, null, System.currentTimeMillis());
@@ -2854,8 +2888,8 @@
         // Limit the number of notifications that any given package except the android
         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
         if (!isSystemNotification && !isNotificationFromListener) {
-            synchronized (mNotificationList) {
-                if(mNotificationsByKey.get(n.getKey()) != null) {
+            synchronized (mNotificationLock) {
+                if (mNotificationsByKey.get(n.getKey()) != null) {
                     // this is an update, rate limit updates only
                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
@@ -2913,7 +2947,7 @@
 
         // setup local book-keeping
         final NotificationRecord r = new NotificationRecord(getContext(), n);
-        synchronized (mEnqueuedNotifications) {
+        synchronized (mNotificationLock) {
             mEnqueuedNotifications.add(r);
         }
         mHandler.post(new EnqueueNotificationRunnable(userId, r));
@@ -2932,7 +2966,7 @@
 
         @Override
         public void run() {
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) {
                     // TODO: log to event log
                     if (DBG) {
@@ -3027,9 +3061,9 @@
 
         @Override
         public void run() {
-            try {
-                NotificationRecord r = null;
-                synchronized (mEnqueuedNotifications) {
+            synchronized (mNotificationLock) {
+                try {
+                    NotificationRecord r = null;
                     int N = mEnqueuedNotifications.size();
                     for (int i = 0; i < N; i++) {
                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
@@ -3038,12 +3072,10 @@
                             break;
                         }
                     }
-                }
-                if (r == null) {
-                    Slog.e(TAG, "Cannot find enqueued record for key: " + key);
-                    return;
-                }
-                synchronized (mNotificationList) {
+                    if (r == null) {
+                        Slog.i(TAG, "Cannot find enqueued record for key: " + key);
+                        return;
+                    }
                     NotificationRecord old = mNotificationsByKey.get(key);
                     final StatusBarNotification n = r.sbn;
                     final Notification notification = n.getNotification();
@@ -3102,9 +3134,7 @@
                     }
 
                     buzzBeepBlinkLocked(r);
-                }
-            } finally {
-                synchronized (mEnqueuedNotifications) {
+                } finally {
                     int N = mEnqueuedNotifications.size();
                     for (int i = 0; i < N; i++) {
                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
@@ -3161,8 +3191,7 @@
         // notification was a summary and the new one isn't, or when the old
         // notification was a summary and its group key changed.
         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
-            cancelGroupChildrenLocked(old, callingUid, callingPid, null,
-                    REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
+            cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
         }
     }
 
@@ -3289,7 +3318,9 @@
     private boolean playSound(final NotificationRecord record, Uri soundUri) {
         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
         // do not play notifications if there is a user of exclusive audio focus
-        if (!mAudioManager.isAudioFocusExclusive()) {
+        // or the device is in vibrate mode
+        if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
+                != AudioManager.RINGER_MODE_VIBRATE) {
             final long identity = Binder.clearCallingIdentity();
             try {
                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
@@ -3429,7 +3460,7 @@
         RankingReconsideration recon = (RankingReconsideration) message.obj;
         recon.run();
         boolean changed;
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
             if (record == null) {
                 return;
@@ -3457,7 +3488,7 @@
     private void handleRankingSort(Message msg) {
         if (!(msg.obj instanceof Boolean)) return;
         boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             final int N = mNotificationList.size();
             ArrayList<String> orderBefore = new ArrayList<String>(N);
             ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
@@ -3514,7 +3545,7 @@
     }
 
     private void handleSendRankingUpdate() {
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             mListeners.notifyRankingUpdateLocked();
         }
     }
@@ -3533,19 +3564,23 @@
     }
 
     private void handleListenerHintsChanged(int hints) {
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             mListeners.notifyListenerHintsChangedLocked(hints);
         }
     }
 
     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
         }
     }
 
     private final class WorkerHandler extends Handler
     {
+        public WorkerHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg)
         {
@@ -3631,6 +3666,17 @@
     }
 
     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
+        final String canceledKey = r.getKey();
+
+        // Remove from either list
+        boolean wasPosted;
+        if (mNotificationList.remove(r)) {
+            mNotificationsByKey.remove(r.sbn.getKey());
+            wasPosted = true;
+        } else {
+            mEnqueuedNotifications.remove(r);
+            wasPosted = false;
+        }
 
         // Record caller.
         recordCallerLocked(r);
@@ -3648,50 +3694,51 @@
             }
         }
 
-        // status bar
-        if (r.getNotification().getSmallIcon() != null) {
-            r.isCanceled = true;
-            mListeners.notifyRemovedLocked(r.sbn, reason);
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mGroupHelper.onNotificationRemoved(r.sbn);
+        // Only cancel these if this notification actually got to be posted.
+        if (wasPosted) {
+            // status bar
+            if (r.getNotification().getSmallIcon() != null) {
+                r.isCanceled = true;
+                mListeners.notifyRemovedLocked(r.sbn, reason);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mGroupHelper.onNotificationRemoved(r.sbn);
+                    }
+                });
+            }
+
+            // sound
+            if (canceledKey.equals(mSoundNotificationKey)) {
+                mSoundNotificationKey = null;
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
+                    if (player != null) {
+                        player.stopAsync();
+                    }
+                } catch (RemoteException e) {
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
                 }
-            });
-        }
+            }
 
-        final String canceledKey = r.getKey();
-
-        // sound
-        if (canceledKey.equals(mSoundNotificationKey)) {
-            mSoundNotificationKey = null;
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
-                if (player != null) {
-                    player.stopAsync();
+            // vibrate
+            if (canceledKey.equals(mVibrateNotificationKey)) {
+                mVibrateNotificationKey = null;
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mVibrator.cancel();
                 }
-            } catch (RemoteException e) {
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+                finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
-        }
 
-        // vibrate
-        if (canceledKey.equals(mVibrateNotificationKey)) {
-            mVibrateNotificationKey = null;
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mVibrator.cancel();
-            }
-            finally {
-                Binder.restoreCallingIdentity(identity);
-            }
+            // light
+            mLights.remove(canceledKey);
         }
 
-        // light
-        mLights.remove(canceledKey);
-
         // Record usage stats
         // TODO: add unbundling stats?
         switch (reason) {
@@ -3707,10 +3754,9 @@
                 break;
         }
 
-        mNotificationsByKey.remove(r.sbn.getKey());
         String groupKey = r.getGroupKey();
         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
-        if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
+        if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
             mSummaryByGroupKey.remove(groupKey);
         }
         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
@@ -3745,10 +3791,11 @@
                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
 
-                synchronized (mNotificationList) {
-                    int index = indexOfNotificationLocked(pkg, tag, id, userId);
-                    if (index >= 0) {
-                        NotificationRecord r = mNotificationList.get(index);
+                synchronized (mNotificationLock) {
+                    // Look for the notification, searching both the posted and enqueued lists.
+                    NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
+                    if (r != null) {
+                        // The notification was found, check if it should be removed.
 
                         // Ideally we'd do this in the caller of this method. However, that would
                         // require the caller to also find the notification.
@@ -3763,13 +3810,13 @@
                             return;
                         }
 
-                        mNotificationList.remove(index);
-
+                        // Cancel the notification.
                         cancelNotificationLocked(r, sendDelete, reason);
                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
-                                REASON_GROUP_SUMMARY_CANCELED, sendDelete);
+                                sendDelete);
                         updateLightsLocked();
                     } else {
+                        // No notification was found, assume that it is snoozed and cancel it.
                         final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
                         if (wasSnoozed) {
                             savePolicyFile();
@@ -3808,120 +3855,131 @@
      * Cancels all notifications from a given package that have all of the
      * {@code mustHaveFlags}.
      */
-    boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
+    void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
             ManagedServiceInfo listener) {
-        String listenerName = listener == null ? null : listener.component.toShortString();
-        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
-                pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
-                listenerName);
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                String listenerName = listener == null ? null : listener.component.toShortString();
+                EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
+                        pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
+                        listenerName);
 
-        synchronized (mNotificationList) {
-            final int N = mNotificationList.size();
-            ArrayList<NotificationRecord> canceledNotifications = null;
-            for (int i = N-1; i >= 0; --i) {
-                NotificationRecord r = mNotificationList.get(i);
-                if (!notificationMatchesUserId(r, userId)) {
-                    continue;
-                }
-                // Don't remove notifications to all, if there's no package name specified
-                if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
-                    continue;
-                }
-                if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
-                    continue;
-                }
-                if ((r.getFlags() & mustNotHaveFlags) != 0) {
-                    continue;
-                }
-                if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
-                    continue;
-                }
-                if (channelId != null && !channelId.equals(r.getChannel().getId())) {
-                    continue;
-                }
-                if (canceledNotifications == null) {
-                    canceledNotifications = new ArrayList<>();
-                }
-                canceledNotifications.add(r);
+                // Why does this parameter exist? Do we actually want to execute the above if doit
+                // is false?
                 if (!doit) {
-                    return true;
+                    return;
                 }
-                mNotificationList.remove(i);
-                cancelNotificationLocked(r, false, reason);
-            }
-            mSnoozeHelper.cancel(userId, pkg);
-            if (doit && canceledNotifications != null) {
-                final int M = canceledNotifications.size();
-                for (int i = 0; i < M; i++) {
-                    cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
-                            listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
+
+                synchronized (mNotificationLock) {
+                    FlagChecker flagChecker = (int flags) -> {
+                        if ((flags & mustHaveFlags) != mustHaveFlags) {
+                            return false;
+                        }
+                        if ((flags & mustNotHaveFlags) != 0) {
+                            return false;
+                        }
+                        return true;
+                    };
+
+                    cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
+                            pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
+                            false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
+                            listenerName);
+                    cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
+                            callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
+                            flagChecker, false /*includeCurrentProfiles*/, userId,
+                            false /*sendDelete*/, reason, listenerName);
+                    mSnoozeHelper.cancel(userId, pkg);
                 }
             }
-            if (canceledNotifications != null) {
-                updateLightsLocked();
+        });
+    }
+
+    private interface FlagChecker {
+        // Returns false if these flags do not pass the defined flag test.
+        public boolean apply(int flags);
+    }
+
+    private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
+            int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
+            String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
+            boolean sendDelete, int reason, String listenerName) {
+        ArrayList<NotificationRecord> canceledNotifications = null;
+        for (int i = notificationList.size() - 1; i >= 0; --i) {
+            NotificationRecord r = notificationList.get(i);
+            if (includeCurrentProfiles) {
+                if (!notificationMatchesCurrentProfiles(r, userId)) {
+                    continue;
+                }
+            } else if (!notificationMatchesUserId(r, userId)) {
+                continue;
             }
-            return canceledNotifications != null;
+            // Don't remove notifications to all, if there's no package name specified
+            if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
+                continue;
+            }
+            if (!flagChecker.apply(r.getFlags())) {
+                continue;
+            }
+            if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
+                continue;
+            }
+            if (channelId != null && !channelId.equals(r.getChannel().getId())) {
+                continue;
+            }
+
+            if (canceledNotifications == null) {
+                canceledNotifications = new ArrayList<>();
+            }
+            canceledNotifications.add(r);
+            cancelNotificationLocked(r, sendDelete, reason);
+        }
+        if (canceledNotifications != null) {
+            final int M = canceledNotifications.size();
+            for (int i = 0; i < M; i++) {
+                cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
+                        listenerName, false /* sendDelete */);
+            }
+            updateLightsLocked();
         }
     }
 
-    void snoozeNotificationInt(String key, String snoozeCriterionId, ManagedServiceInfo listener) {
+    void snoozeNotificationInt(String key, long until, String snoozeCriterionId,
+            ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
         // TODO: write to event log
         if (DBG) {
-            Slog.d(TAG, String.format("snooze event(%s, %s, %s)",
-                    key, snoozeCriterionId, listenerName));
+            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, until, snoozeCriterionId,
+                    listenerName));
         }
-        synchronized (mNotificationList) {
-            final NotificationRecord r = mNotificationsByKey.get(key);
-            if (r != null) {
-                mNotificationList.remove(r);
-                cancelNotificationLocked(r, false, REASON_SNOOZED);
-                mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, snoozeCriterionId);
-                updateLightsLocked();
-                mSnoozeHelper.snooze(r);
-                savePolicyFile();
-            }
-        }
-    }
-
-    void snoozeNotificationInt(String key, long until, ManagedServiceInfo listener) {
-        String listenerName = listener == null ? null : listener.component.toShortString();
-        // TODO: write to event log
-        if (DBG) {
-            Slog.d(TAG, String.format("snooze event(%s, %d, %s)", key, until, listenerName));
-        }
-        if (until < System.currentTimeMillis()) {
+        if (until != SNOOZE_UNTIL_UNSPECIFIED && until < System.currentTimeMillis()) {
             return;
         }
-        synchronized (mNotificationList) {
-            final NotificationRecord r = mNotificationsByKey.get(key);
-            if (r != null) {
-                mNotificationList.remove(r);
-                cancelNotificationLocked(r, false, REASON_SNOOZED);
-                updateLightsLocked();
-                mSnoozeHelper.snooze(r, until);
-                savePolicyFile();
+        // Needs to post so that it can cancel notifications not yet enqueued.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (mNotificationLock) {
+                    final NotificationRecord r = findNotificationByKeyLocked(key);
+                    if (r != null) {
+                        cancelNotificationLocked(r, false, REASON_SNOOZED);
+                        updateLightsLocked();
+                        if (snoozeCriterionId != null) {
+                            mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn,
+                                    snoozeCriterionId);
+                        }
+                        if (until == SNOOZE_UNTIL_UNSPECIFIED) {
+                            mSnoozeHelper.snooze(r);
+                        } else {
+                            mSnoozeHelper.snooze(r, until);
+                        }
+                        savePolicyFile();
+                    }
+                }
             }
-        }
-    }
-
-    void snoozeNotificationInt(String key, ManagedServiceInfo listener) {
-        String listenerName = listener == null ? null : listener.component.toShortString();
-        // TODO: write to event log
-        if (DBG) {
-            Slog.d(TAG, String.format("snooze event(%s, %s)", key, listenerName));
-        }
-        synchronized (mNotificationList) {
-            final NotificationRecord r = mNotificationsByKey.get(key);
-            if (r != null) {
-                mNotificationList.remove(r);
-                cancelNotificationLocked(r, false, REASON_SNOOZED);
-                updateLightsLocked();
-                mSnoozeHelper.snooze(r);
-                savePolicyFile();
-            }
-        }
+        });
     }
 
     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
@@ -3936,47 +3994,40 @@
 
     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
-        String listenerName = listener == null ? null : listener.component.toShortString();
-        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
-                null, userId, 0, 0, reason, listenerName);
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (mNotificationLock) {
+                    String listenerName =
+                            listener == null ? null : listener.component.toShortString();
+                    EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
+                            null, userId, 0, 0, reason, listenerName);
 
-        ArrayList<NotificationRecord> canceledNotifications = null;
-        final int N = mNotificationList.size();
-        for (int i=N-1; i>=0; i--) {
-            NotificationRecord r = mNotificationList.get(i);
-            if (includeCurrentProfiles) {
-                if (!notificationMatchesCurrentProfiles(r, userId)) {
-                    continue;
-                }
-            } else {
-                if (!notificationMatchesUserId(r, userId)) {
-                    continue;
+                    FlagChecker flagChecker = (int flags) -> {
+                        if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
+                                != 0) {
+                            return false;
+                        }
+                        return true;
+                    };
+
+                    cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
+                            null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
+                            includeCurrentProfiles, userId, true /*sendDelete*/, reason,
+                            listenerName);
+                    cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
+                            callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
+                            flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
+                            reason, listenerName);
+                    mSnoozeHelper.cancel(userId, includeCurrentProfiles);
                 }
             }
-
-            if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
-                            | Notification.FLAG_NO_CLEAR)) == 0) {
-                mNotificationList.remove(i);
-                cancelNotificationLocked(r, true, reason);
-                // Make a note so we can cancel children later.
-                if (canceledNotifications == null) {
-                    canceledNotifications = new ArrayList<>();
-                }
-                canceledNotifications.add(r);
-            }
-        }
-        mSnoozeHelper.cancel(userId, includeCurrentProfiles);
-        int M = canceledNotifications != null ? canceledNotifications.size() : 0;
-        for (int i = 0; i < M; i++) {
-            cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
-                    listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
-        }
-        updateLightsLocked();
+        });
     }
 
     // Warning: The caller is responsible for invoking updateLightsLocked().
     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
-            String listenerName, int reason, boolean sendDelete) {
+            String listenerName, boolean sendDelete) {
         Notification n = r.getNotification();
         if (!n.isGroupSummary()) {
             return;
@@ -3990,16 +4041,26 @@
             return;
         }
 
-        final int N = mNotificationList.size();
-        for (int i = N - 1; i >= 0; i--) {
-            NotificationRecord childR = mNotificationList.get(i);
-            StatusBarNotification childSbn = childR.sbn;
+        cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
+                sendDelete);
+        cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
+                listenerName, sendDelete);
+    }
+
+    private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
+            NotificationRecord parentNotification, int callingUid, int callingPid,
+            String listenerName, boolean sendDelete) {
+        final String pkg = parentNotification.sbn.getPackageName();
+        final int userId = parentNotification.getUserId();
+        final int reason = REASON_GROUP_SUMMARY_CANCELED;
+        for (int i = notificationList.size() - 1; i >= 0; i--) {
+            final NotificationRecord childR = notificationList.get(i);
+            final StatusBarNotification childSbn = childR.sbn;
             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
-                    childR.getGroupKey().equals(r.getGroupKey())
+                    childR.getGroupKey().equals(parentNotification.getGroupKey())
                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
-                mNotificationList.remove(i);
                 cancelNotificationLocked(childR, sendDelete, reason);
             }
         }
@@ -4048,19 +4109,49 @@
         }
     }
 
-    // lock on mNotificationList
-    int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
+    // Searches both enqueued and posted notifications by key.
+    // TODO: need to combine a bunch of these getters with slightly different behavior.
+    // TODO: Should enqueuing just add to mNotificationsByKey instead?
+    private NotificationRecord findNotificationByKeyLocked(String key) {
+        final int N = mNotificationList.size();
+        for (int i = 0; i < N; i++) {
+            if (key.equals(mNotificationList.get(i).getKey())) {
+                return mNotificationList.get(i);
+            }
+        }
+        final int M = mEnqueuedNotifications.size();
+        for (int i = 0; i < M; i++) {
+            if (key.equals(mEnqueuedNotifications.get(i).getKey())) {
+                return mEnqueuedNotifications.get(i);
+            }
+        }
+        return null;
+    }
+
+    private NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
+        NotificationRecord r;
+        if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
+            return r;
+        }
+        if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
+                != null) {
+            return r;
+        }
+        return null;
+    }
+
+    private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
+            String pkg, String tag, int id, int userId)
     {
-        ArrayList<NotificationRecord> list = mNotificationList;
         final int len = list.size();
-        for (int i=0; i<len; i++) {
+        for (int i = 0; i < len; i++) {
             NotificationRecord r = list.get(i);
             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
-                return i;
+                return r;
             }
         }
-        return -1;
+        return null;
     }
 
     // lock on mNotificationList
@@ -4075,7 +4166,7 @@
     }
 
     private void updateNotificationPulse() {
-        synchronized (mNotificationList) {
+        synchronized (mNotificationLock) {
             updateLightsLocked();
         }
     }
@@ -4379,7 +4470,7 @@
         public void onServiceAdded(ManagedServiceInfo info) {
             final INotificationListener listener = (INotificationListener) info.service;
             final NotificationRankingUpdate update;
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 update = makeRankingUpdateLocked(info);
             }
             try {
@@ -4574,12 +4665,12 @@
             }
         }
 
-        private boolean isListenerPackage(String packageName) {
+        public boolean isListenerPackage(String packageName) {
             if (packageName == null) {
                 return false;
             }
             // TODO: clean up locking object later
-            synchronized (mNotificationList) {
+            synchronized (mNotificationLock) {
                 for (final ManagedServiceInfo serviceInfo : mServices) {
                     if (packageName.equals(serviceInfo.component.getPackageName())) {
                         return true;
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 5c1e99c..c2cef09 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -27,8 +27,10 @@
             boolean fromTargetApp);
     void updateNotificationChannel(String pkg, int uid, NotificationChannel channel);
     void updateNotificationChannelFromAssistant(String pkg, int uid, NotificationChannel channel);
-    NotificationChannel getNotificationChannel(String pkg, int uid, String channelId);
-    NotificationChannel getNotificationChannelWithFallback(String pkg, int uid, String channelId);
+    NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted);
+    NotificationChannel getNotificationChannelWithFallback(String pkg, int uid, String channelId, boolean includeDeleted);
     void deleteNotificationChannel(String pkg, int uid, String channelId);
-    ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid);
+    void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
+    void permanentlyDeleteNotificationChannels(String pkg, int uid);
+    ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 3fcce3c..e44fb7f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -18,6 +18,7 @@
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import android.app.Notification;
@@ -29,7 +30,6 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.os.Build;
-import android.os.Process;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
@@ -432,9 +432,13 @@
         if (IMPORTANCE_NONE == r.importance) {
             throw new IllegalArgumentException("Package blocked");
         }
-        if (r.channels.containsKey(channel.getId()) || channel.getName().equals(
-                mContext.getString(R.string.default_notification_channel_label))) {
-            // Channel already exists, no-op.
+        NotificationChannel existing = r.channels.get(channel.getId());
+        // Keep existing settings
+        if (existing != null) {
+            if (existing.isDeleted()) {
+                existing.setDeleted(false);
+                updateConfig();
+            }
             return;
         }
         if (channel.getImportance() < NotificationManager.IMPORTANCE_NONE
@@ -471,7 +475,7 @@
             throw new IllegalArgumentException("Invalid package");
         }
         NotificationChannel channel = r.channels.get(updatedChannel.getId());
-        if (channel == null) {
+        if (channel == null || channel.isDeleted()) {
             throw new IllegalArgumentException("Channel does not exist");
         }
         if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
@@ -489,7 +493,7 @@
             throw new IllegalArgumentException("Invalid package");
         }
         NotificationChannel channel = r.channels.get(updatedChannel.getId());
-        if (channel == null) {
+        if (channel == null || channel.isDeleted()) {
             throw new IllegalArgumentException("Channel does not exist");
         }
 
@@ -519,6 +523,9 @@
         if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_SHOW_BADGE) == 0) {
             channel.setShowBadge(updatedChannel.canShowBadge());
         }
+        if (updatedChannel.isDeleted()) {
+            updatedChannel.setDeleted(true);
+        }
 
         r.channels.put(channel.getId(), channel);
         updateConfig();
@@ -526,13 +533,13 @@
 
     @Override
     public NotificationChannel getNotificationChannelWithFallback(String pkg, int uid,
-            String channelId) {
+            String channelId, boolean includeDeleted) {
         Record r = getOrCreateRecord(pkg, uid);
         if (channelId == null) {
             channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
         }
         NotificationChannel channel = r.channels.get(channelId);
-        if (channel != null) {
+        if (channel != null && (includeDeleted || !channel.isDeleted())) {
             return channel;
         } else {
             return r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID);
@@ -540,16 +547,21 @@
     }
 
     @Override
-    public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId) {
+    public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
+            boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
         Record r = getOrCreateRecord(pkg, uid);
         if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
+            return null;
         }
         if (channelId == null) {
             channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
         }
-        return r.channels.get(channelId);
+        final NotificationChannel nc = r.channels.get(channelId);
+        if (nc != null && (includeDeleted || !nc.isDeleted())) {
+            return nc;
+        }
+        return null;
     }
 
     @Override
@@ -558,24 +570,57 @@
         Preconditions.checkNotNull(channelId);
         Record r = getRecord(pkg, uid);
         if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
+            return;
         }
-        if (r != null) {
-            r.channels.remove(channelId);
+        NotificationChannel channel = r.channels.get(channelId);
+        if (channel != null) {
+            channel.setDeleted(true);
         }
     }
 
     @Override
-    public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid) {
+    @VisibleForTesting
+    public void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId) {
+        Preconditions.checkNotNull(pkg);
+        Preconditions.checkNotNull(channelId);
+        Record r = getRecord(pkg, uid);
+        if (r == null) {
+            return;
+        }
+        r.channels.remove(channelId);
+    }
+
+    @Override
+    public void permanentlyDeleteNotificationChannels(String pkg, int uid) {
+        Preconditions.checkNotNull(pkg);
+        Record r = getRecord(pkg, uid);
+        if (r == null) {
+            return;
+        }
+        int N = r.channels.size() - 1;
+        for (int i = N; i >= 0; i--) {
+            String key = r.channels.keyAt(i);
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
+                r.channels.remove(key);
+            }
+        }
+    }
+
+    @Override
+    public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
+            boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
         List<NotificationChannel> channels = new ArrayList<>();
         Record r = getRecord(pkg, uid);
         if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
+            return ParceledListSlice.emptyList();
         }
         int N = r.channels.size();
         for (int i = 0; i < N; i++) {
-            channels.add(r.channels.valueAt(i));
+            final NotificationChannel nc = r.channels.valueAt(i);
+            if (includeDeleted || !nc.isDeleted()) {
+                channels.add(nc);
+            }
         }
         return new ParceledListSlice<>(channels);
     }
@@ -738,30 +783,46 @@
         return packageBans;
     }
 
-    public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList) {
-        if (removingPackage || pkgList == null || pkgList.length == 0) {
+    public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
+            int[] uidList) {
+        if (pkgList == null || pkgList.length == 0) {
             return; // nothing to do
         }
         boolean updated = false;
-        for (String pkg : pkgList) {
-            final Record r = mRestoredWithoutUids.get(pkg);
-            if (r != null) {
+        if (removingPackage) {
+            // Remove notification settings for uninstalled package
+            int size = Math.min(pkgList.length, uidList.length);
+            for (int i = 0; i < size; i++) {
+                final String pkg = pkgList[i];
+                final int uid = uidList[i];
+                mRecords.remove(recordKey(pkg, uid));
+                mRestoredWithoutUids.remove(pkg);
+                updated = true;
+            }
+        } else {
+            for (String pkg : pkgList) {
+                // Package install
+                final Record r = mRestoredWithoutUids.get(pkg);
+                if (r != null) {
+                    try {
+                        r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
+                        mRestoredWithoutUids.remove(pkg);
+                        mRecords.put(recordKey(r.pkg, r.uid), r);
+                        updated = true;
+                    } catch (NameNotFoundException e) {
+                        // noop
+                    }
+                }
+                // Package upgrade
                 try {
-                    r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
-                    mRestoredWithoutUids.remove(pkg);
-                    mRecords.put(recordKey(r.pkg, r.uid), r);
-                    updated = true;
+                    Record fullRecord = getRecord(pkg,
+                            mPm.getPackageUidAsUser(pkg, changeUserId));
+                    if (fullRecord != null) {
+                        clampDefaultChannel(fullRecord);
+                    }
                 } catch (NameNotFoundException e) {
-                    // noop
                 }
             }
-            try {
-                Record fullRecord = getRecord(pkg,
-                        mPm.getPackageUidAsUser(pkg, changeUserId));
-                if (fullRecord != null) {
-                    clampDefaultChannel(fullRecord);
-                }
-            } catch (NameNotFoundException e) {}
         }
 
         if (updated) {
diff --git a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
index 1e3e0ca..3d946e0 100644
--- a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
+++ b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
@@ -27,10 +28,13 @@
 import android.graphics.drawable.Drawable;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.Xml;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
@@ -51,6 +55,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -62,7 +67,7 @@
 class EphemeralApplicationRegistry {
     private static final boolean DEBUG = false;
 
-    private static final boolean ENABLED = false;
+    private static final boolean ENABLED = true;
 
     private static final String LOG_TAG = "EphemeralAppRegistry";
 
@@ -90,6 +95,16 @@
     @GuardedBy("mService.mPackages")
     private SparseArray<List<UninstalledEphemeralAppState>> mUninstalledEphemeralApps;
 
+    /**
+     * Automatic grants for access to instant app metadata.
+     * The key is the target application UID.
+     * The value is a set of instant app UIDs.
+     * UserID -> TargetAppId -> InstantAppId
+     */
+    private SparseArray<SparseArray<SparseBooleanArray>> mEphemeralGrants;
+    /** The set of all installed instant apps. UserID -> AppID */
+    private SparseArray<SparseBooleanArray> mInstalledEphemeralAppUids;
+
     public EphemeralApplicationRegistry(PackageManagerService service) {
         mService = service;
     }
@@ -188,7 +203,11 @@
             }
 
             // Propagate permissions before removing any state
-            propagateEphemeralAppPermissionsIfNeeded(pkg, userId);
+            // TODO: Fix this later
+            // propagateEphemeralAppPermissionsIfNeeded(pkg, userId);
+            if (pkg.applicationInfo.isEphemeralApp()) {
+                addEphemeralAppLPw(userId, ps.appId);
+            }
 
             // Remove the in-memory state
             if (mUninstalledEphemeralApps != null) {
@@ -248,9 +267,11 @@
             if (pkg.applicationInfo.isEphemeralApp()) {
                 // Add a record for an uninstalled ephemeral app
                 addUninstalledEphemeralAppLPw(pkg, userId);
+                removeEphemeralAppLPw(userId, ps.appId);
             } else {
                 // Deleting an app prunes all ephemeral state such as cookie
                 deleteDir(getEphemeralApplicationDir(pkg.packageName, userId));
+                removeAppLPw(userId, ps.appId);
             }
         }
     }
@@ -262,9 +283,114 @@
         if (mUninstalledEphemeralApps != null) {
             mUninstalledEphemeralApps.remove(userId);
         }
+        if (mInstalledEphemeralAppUids != null) {
+            mInstalledEphemeralAppUids.remove(userId);
+        }
+        if (mEphemeralGrants != null) {
+            mEphemeralGrants.remove(userId);
+        }
         deleteDir(getEphemeralApplicationsDir(userId));
     }
 
+    public boolean isEphemeralAccessGranted(int userId, int targetAppId, int ephemeralAppId) {
+        if (mEphemeralGrants == null) {
+            return false;
+        }
+        final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
+        if (targetAppList == null) {
+            return false;
+        }
+        final SparseBooleanArray ephemeralGrantList = targetAppList.get(targetAppId);
+        if (ephemeralGrantList == null) {
+            return false;
+        }
+        return ephemeralGrantList.get(ephemeralAppId);
+    }
+
+    public void grantEphemeralAccessLPw(int userId, Intent intent,
+            int targetAppId, int ephemeralAppId) {
+        if (mInstalledEphemeralAppUids == null) {
+            return;     // no ephemeral apps installed; no need to grant
+        }
+        SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId);
+        if (ephemeralAppList == null || !ephemeralAppList.get(ephemeralAppId)) {
+            return;     // ephemeral app id isn't installed; no need to grant
+        }
+        if (ephemeralAppList.get(targetAppId)) {
+            return;     // target app id is an ephemeral app; no need to grant
+        }
+        if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
+            final Set<String> categories = intent.getCategories();
+            if (categories != null && categories.contains(Intent.CATEGORY_BROWSABLE)) {
+                return;  // launched via VIEW/BROWSABLE intent; no need to grant
+            }
+        }
+        if (mEphemeralGrants == null) {
+            mEphemeralGrants = new SparseArray<>();
+        }
+        SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
+        if (targetAppList == null) {
+            targetAppList = new SparseArray<>();
+            mEphemeralGrants.put(userId, targetAppList);
+        }
+        SparseBooleanArray ephemeralGrantList = targetAppList.get(targetAppId);
+        if (ephemeralGrantList == null) {
+            ephemeralGrantList = new SparseBooleanArray();
+            targetAppList.put(targetAppId, ephemeralGrantList);
+        }
+        ephemeralGrantList.put(ephemeralAppId, true /*granted*/);
+    }
+
+    public void addEphemeralAppLPw(int userId, int ephemeralAppId) {
+        if (mInstalledEphemeralAppUids == null) {
+            mInstalledEphemeralAppUids = new SparseArray<>();
+        }
+        SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId);
+        if (ephemeralAppList == null) {
+            ephemeralAppList = new SparseBooleanArray();
+            mInstalledEphemeralAppUids.put(userId, ephemeralAppList);
+        }
+        ephemeralAppList.put(ephemeralAppId, true /*installed*/);
+    }
+
+    private void removeEphemeralAppLPw(int userId, int ephemeralAppId) {
+        // remove from the installed list
+        if (mInstalledEphemeralAppUids == null) {
+            return; // no ephemeral apps on the system
+        }
+        final SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId);
+        if (ephemeralAppList == null) {
+            Slog.w(LOG_TAG, "Remove ephemeral not in install list");
+            return;
+        } else {
+            ephemeralAppList.delete(ephemeralAppId);
+        }
+        // remove any grants
+        if (mEphemeralGrants == null) {
+            return; // no grants on the system
+        }
+        final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
+        if (targetAppList == null) {
+            return; // no grants for this user
+        }
+        final int numApps = targetAppList.size();
+        for (int i = targetAppList.size() - 1; i >= 0; --i) {
+            targetAppList.valueAt(i).delete(ephemeralAppId);
+        }
+    }
+
+    private void removeAppLPw(int userId, int targetAppId) {
+        // remove from the installed list
+        if (mEphemeralGrants == null) {
+            return; // no grants on the system
+        }
+        final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId);
+        if (targetAppList == null) {
+            return; // no grants for this user
+        }
+        targetAppList.delete(targetAppId);
+    }
+
     private void addUninstalledEphemeralAppLPw(PackageParser.Package pkg, int userId) {
         EphemeralApplicationInfo uninstalledApp = createEphemeralAppInfoForPackage(pkg, userId);
         if (uninstalledApp == null) {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 98249dd1..0130e30 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -242,6 +242,16 @@
         }
     }
 
+    public void setAppQuota(String uuid, int userId, int appId, long cacheQuota)
+            throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            mInstalld.setAppQuota(uuid, userId, appId, cacheQuota);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
             int dexoptNeeded, @Nullable String outputPath, int dexFlags,
             String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries)
@@ -351,10 +361,10 @@
         }
     }
 
-    public void freeCache(String uuid, long freeStorageSize) throws InstallerException {
+    public void freeCache(String uuid, long freeStorageSize, int flags) throws InstallerException {
         if (!checkBeforeRemote()) return;
         try {
-            mInstalld.freeCache(uuid, freeStorageSize);
+            mInstalld.freeCache(uuid, freeStorageSize, flags);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
@@ -415,6 +425,15 @@
         }
     }
 
+    public void invalidateMounts() throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            mInstalld.invalidateMounts();
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 48e000d8..a74e141 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -21,9 +21,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
@@ -229,11 +231,15 @@
             long ident = injectClearCallingIdentity();
             try {
                 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
+                if (callingUserInfo.isManagedProfile()) {
+                    throw new SecurityException(message + " for another profile " + targetUserId);
+                }
+
                 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
                 if (targetUserInfo == null
                         || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
                         || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) {
-                    throw new SecurityException(message);
+                    throw new SecurityException(message + " for unrelated profile " + targetUserId);
                 }
             } finally {
                 injectRestoreCallingIdentity(ident);
@@ -277,30 +283,17 @@
         @Override
         public ParceledListSlice<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
-            if (!isUserEnabled(user)) {
-                return null;
-            }
-
-            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
-            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            mainIntent.setPackage(packageName);
-            long ident = Binder.clearCallingIdentity();
-            try {
-                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                        user.getIdentifier());
-                return new ParceledListSlice<>(apps);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            return queryActivitiesForUser(
+                    new Intent(Intent.ACTION_MAIN)
+                            .addCategory(Intent.CATEGORY_LAUNCHER)
+                            .setPackage(packageName),
+                    user);
         }
 
         @Override
         public ActivityInfo resolveActivity(ComponentName component, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot resolve activity");
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -318,9 +311,56 @@
         }
 
         @Override
+        public ParceledListSlice getShortcutConfigActivities(String packageName, UserHandle user)
+                throws RemoteException {
+            return queryActivitiesForUser(
+                    new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user);
+        }
+
+        private ParceledListSlice<ResolveInfo> queryActivitiesForUser(Intent intent,
+                UserHandle user) {
+            ensureInUserProfiles(user, "Cannot retrieve activities");
+            if (!isUserEnabled(user)) {
+                return null;
+            }
+
+            long ident = injectClearCallingIdentity();
+            try {
+                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
+                return new ParceledListSlice<>(apps);
+            } finally {
+                injectRestoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public IntentSender getShortcutConfigActivityIntent(String callingPackage,
+                ComponentName component, UserHandle user) throws RemoteException {
+            ensureShortcutPermission(callingPackage, user);
+            Preconditions.checkNotNull(component);
+            Preconditions.checkArgument(isUserEnabled(user), "User not enabled");
+
+            // All right, create the sender.
+            Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return PendingIntent.getActivityAsUser(
+                        mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
+                                | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
+                        null, user)
+                        .getIntentSender();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public boolean isPackageEnabled(String packageName, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot check package");
             if (!isUserEnabled(user)) {
                 return false;
             }
@@ -341,7 +381,7 @@
         @Override
         public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot check package");
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -363,7 +403,7 @@
 
         private void ensureShortcutPermission(@NonNull String callingPackage, int userId) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(userId, "Cannot access shortcuts for unrelated profile " + userId);
+            ensureInUserProfiles(userId, "Cannot access shortcuts");
 
             if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
                     callingPackage)) {
@@ -439,7 +479,7 @@
         public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
                 Rect sourceBounds, Bundle startActivityOptions, int userId) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(userId, "Cannot start activity for unrelated profile " + userId);
+            ensureInUserProfiles(userId, "Cannot start activity");
 
             if (!isUserEnabled(userId)) {
                 throw new IllegalStateException("Cannot start a shortcut for disabled profile "
@@ -492,7 +532,7 @@
         @Override
         public boolean isActivityEnabled(ComponentName component, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot check component");
             if (!isUserEnabled(user)) {
                 return false;
             }
@@ -513,7 +553,7 @@
         @Override
         public void startActivityAsUser(ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
-            ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot start activity");
             if (!isUserEnabled(user)) {
                 throw new IllegalStateException("Cannot start activity for disabled profile "  + user);
             }
@@ -566,7 +606,7 @@
         @Override
         public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
-            ensureInUserProfiles(user, "Cannot show app details for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot show app details");
             if (!isUserEnabled(user)) {
                 throw new IllegalStateException("Cannot show app details for disabled profile "
                         + user);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d25abbf..da6a67e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -52,6 +52,7 @@
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
+import android.content.pm.VersionedPackage;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.BitmapFactory;
@@ -145,6 +146,7 @@
     private static final String ATTR_ABI_OVERRIDE = "abiOverride";
     private static final String ATTR_VOLUME_UUID = "volumeUuid";
     private static final String ATTR_NAME = "name";
+    private static final String ATTR_INSTALL_REASON = "installRason";
 
     /** Automatically destroy sessions older than this */
     private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
@@ -412,6 +414,7 @@
         params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
         params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
         params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
+        params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
 
         final File appIconFile = buildAppIconFile(sessionId);
         if (appIconFile.exists()) {
@@ -484,6 +487,7 @@
         writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
         writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
         writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
+        writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
 
         // Persist app icon if changed since last written
         final File appIconFile = buildAppIconFile(session.sessionId);
@@ -866,8 +870,8 @@
     }
 
     @Override
-    public void uninstall(String packageName, String callerPackageName, int flags,
-                IntentSender statusReceiver, int userId) {
+    public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
+                IntentSender statusReceiver, int userId) throws RemoteException {
         final int callingUid = Binder.getCallingUid();
         mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
         if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
@@ -881,24 +885,24 @@
                 callerPackageName);
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
-                statusReceiver, packageName, isDeviceOwner, userId);
+                statusReceiver, versionedPackage.getPackageName(), isDeviceOwner, userId);
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
                     == PackageManager.PERMISSION_GRANTED) {
             // Sweet, call straight through!
-            mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
+            mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
         } else if (isDeviceOwner) {
             // Allow the DeviceOwner to silently delete packages
             // Need to clear the calling identity to get DELETE_PACKAGES permission
             long ident = Binder.clearCallingIdentity();
             try {
-                mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
+                mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
         } else {
             // Take a short detour to confirm with user
             final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
-            intent.setData(Uri.fromParts("package", packageName, null));
+            intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null));
             intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
             adapter.onUserActionRequired(intent);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7362a51..63a5d14 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16,7 +16,11 @@
 
 package com.android.server.pm;
 
+import static android.Manifest.permission.DELETE_PACKAGES;
+import static android.Manifest.permission.INSTALL_PACKAGES;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
+import static android.Manifest.permission.REQUEST_INSTALL_PACKAGES;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -68,6 +72,7 @@
 import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL;
 import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
 import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
 import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
@@ -80,7 +85,6 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDWR;
-
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
@@ -160,10 +164,12 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
+import android.content.pm.VersionedPackage;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.hardware.display.DisplayManager;
@@ -218,6 +224,7 @@
 import android.util.Log;
 import android.util.LogPrinter;
 import android.util.MathUtils;
+import android.util.PackageUtils;
 import android.util.Pair;
 import android.util.PrintStreamPrinter;
 import android.util.Slog;
@@ -415,6 +422,8 @@
     static final int REMOVE_CHATTY = 1<<16;
     static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<17;
 
+    private static final String STATIC_SHARED_LIB_DELIMITER = "_";
+
     private static final int[] EMPTY_INT_ARRAY = new int[0];
 
     /**
@@ -710,16 +719,21 @@
     public static final class SharedLibraryEntry {
         public final String path;
         public final String apk;
+        public final SharedLibraryInfo info;
 
-        SharedLibraryEntry(String _path, String _apk) {
+        SharedLibraryEntry(String _path, String _apk, String name, int version, int type,
+                String declaringPackageName, int declaringPackageVersionCode) {
             path = _path;
             apk = _apk;
+            info = new SharedLibraryInfo(name, version, type, new VersionedPackage(
+                    declaringPackageName, declaringPackageVersionCode), null);
         }
     }
 
     // Currently known shared libraries.
-    final ArrayMap<String, SharedLibraryEntry> mSharedLibraries =
-            new ArrayMap<String, SharedLibraryEntry>();
+    final ArrayMap<String, SparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>();
+    final ArrayMap<String, SparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage =
+            new ArrayMap<>();
 
     // All available activities, for your resolving pleasure.
     final ActivityIntentResolver mActivities =
@@ -1713,9 +1727,11 @@
             }
 
             // Now that we successfully installed the package, grant runtime
-            // permissions if requested before broadcasting the install.
-            if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
-                    >= Build.VERSION_CODES.M) {
+            // permissions if requested before broadcasting the install. Also
+            // for legacy apps in permission review mode we clear the permission
+            // review flag which is used to emulate runtime permissions for
+            // legacy apps.
+            if (grantPermissions) {
                 grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
             }
 
@@ -1761,7 +1777,8 @@
             }
 
             // Send installed broadcasts if the install/update is not ephemeral
-            if (!isEphemeral(res.pkg)) {
+            // and the package is not a static shared lib.
+            if (!isEphemeral(res.pkg) && res.pkg.staticSharedLibName == null) {
                 mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath);
 
                 // Send added for users that see the package for the first time
@@ -1938,9 +1955,10 @@
                 final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(fsUuid);
                 for (PackageSetting ps : packages) {
                     Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten");
-                    deletePackage(ps.name, new LegacyPackageDeleteObserver(null).getBinder(),
+                    deletePackageVersioned(new VersionedPackage(ps.name,
+                            PackageManager.VERSION_CODE_HIGHEST),
+                            new LegacyPackageDeleteObserver(null).getBinder(),
                             UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS);
-
                     // Try very hard to release any references to this package
                     // so we don't risk the system server being killed due to
                     // open FDs
@@ -1958,11 +1976,6 @@
         for (int userId : userIds) {
             grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
         }
-
-        // We could have touched GID membership, so flush out packages.list
-        synchronized (mPackages) {
-            mSettings.writePackageListLPr();
-        }
     }
 
     private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
@@ -1977,6 +1990,9 @@
         final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                 | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 
+        final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+                >= Build.VERSION_CODES.M;
+
         for (String permission : pkg.requestedPermissions) {
             final BasePermission bp;
             synchronized (mPackages) {
@@ -1986,9 +2002,18 @@
                     && (grantedPermissions == null
                            || ArrayUtils.contains(grantedPermissions, permission))) {
                 final int flags = permissionsState.getPermissionFlags(permission, userId);
-                // Installer cannot change immutable permissions.
-                if ((flags & immutableFlags) == 0) {
-                    grantRuntimePermission(pkg.packageName, permission, userId);
+                if (supportsRuntimePermissions) {
+                    // Installer cannot change immutable permissions.
+                    if ((flags & immutableFlags) == 0) {
+                        grantRuntimePermission(pkg.packageName, permission, userId);
+                    }
+                } else if (mPermissionReviewRequired) {
+                    // In permission review mode we clear the review flag when we
+                    // are asked to install the app with all permissions granted.
+                    if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+                        updatePermissionFlags(permission, pkg.packageName,
+                                PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, userId);
+                    }
                 }
             }
         }
@@ -2215,6 +2240,7 @@
             Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
 
             mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
+            mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
 
             File dataDir = Environment.getDataDirectory();
             mAppInstallDir = new File(dataDir, "app");
@@ -2241,9 +2267,12 @@
             }
 
             ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
-            for (int i=0; i<libConfig.size(); i++) {
-                mSharedLibraries.put(libConfig.keyAt(i),
-                        new SharedLibraryEntry(libConfig.valueAt(i), null));
+            final int builtInLibCount = libConfig.size();
+            for (int i = 0; i < builtInLibCount; i++) {
+                String name = libConfig.keyAt(i);
+                String path = libConfig.valueAt(i);
+                addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
+                        SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
             }
 
             mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
@@ -2308,32 +2337,38 @@
                 // to compile them only when we come across an app that uses them (there's
                 // already logic for that in scanPackageLI) but that adds some complexity.
                 for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                    for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
-                        final String lib = libEntry.path;
-                        if (lib == null) {
-                            continue;
-                        }
-
-                        try {
-                            // Shared libraries do not have profiles so we perform a full
-                            // AOT compilation (if needed).
-                            int dexoptNeeded = DexFile.getDexOptNeeded(
-                                    lib, dexCodeInstructionSet,
-                                    getCompilerFilterForReason(REASON_SHARED_APK),
-                                    false /* newProfile */);
-                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                                mInstaller.dexopt(lib, Process.SYSTEM_UID, "*",
-                                        dexCodeInstructionSet, dexoptNeeded, null,
-                                        DEXOPT_PUBLIC,
-                                        getCompilerFilterForReason(REASON_SHARED_APK),
-                                        StorageManager.UUID_PRIVATE_INTERNAL,
-                                        SKIP_SHARED_LIBRARY_CHECK);
+                    final int libCount = mSharedLibraries.size();
+                    for (int i = 0; i < libCount; i++) {
+                        SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+                        final int versionCount = versionedLib.size();
+                        for (int j = 0; j < versionCount; j++) {
+                            SharedLibraryEntry libEntry = versionedLib.valueAt(j);
+                            final String libPath = libEntry.path != null
+                                    ? libEntry.path : libEntry.apk;
+                            if (libPath == null) {
+                                continue;
                             }
-                        } catch (FileNotFoundException e) {
-                            Slog.w(TAG, "Library not found: " + lib);
-                        } catch (IOException | InstallerException e) {
-                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
-                                    + e.getMessage());
+                            try {
+                                // Shared libraries do not have profiles so we perform a full
+                                // AOT compilation (if needed).
+                                int dexoptNeeded = DexFile.getDexOptNeeded(
+                                        libPath, dexCodeInstructionSet,
+                                        getCompilerFilterForReason(REASON_SHARED_APK),
+                                        false /* newProfile */);
+                                if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+                                    mInstaller.dexopt(libPath, Process.SYSTEM_UID, "*",
+                                            dexCodeInstructionSet, dexoptNeeded, null,
+                                            DEXOPT_PUBLIC,
+                                            getCompilerFilterForReason(REASON_SHARED_APK),
+                                            StorageManager.UUID_PRIVATE_INTERNAL,
+                                            SKIP_SHARED_LIBRARY_CHECK);
+                                }
+                            } catch (FileNotFoundException e) {
+                                Slog.w(TAG, "Library not found: " + libPath);
+                            } catch (IOException | InstallerException e) {
+                                Slog.w(TAG, "Cannot dexopt " + libPath + "; is it an APK or JAR? "
+                                        + e.getMessage());
+                            }
                         }
                     }
                 }
@@ -2627,7 +2662,7 @@
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
-            updateAllSharedLibrariesLPw();
+            updateAllSharedLibrariesLPw(null);
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 // NOTE: We ignore potential failures here during a system scan (like
@@ -2764,9 +2799,11 @@
                 mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                         mIntentFilterVerifierComponent);
                 mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
-                        PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
+                        PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES,
+                        SharedLibraryInfo.VERSION_UNDEFINED);
                 mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
-                        PackageManager.SYSTEM_SHARED_LIBRARY_SHARED);
+                        PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
+                        SharedLibraryInfo.VERSION_UNDEFINED);
             } else {
                 mRequiredVerifierPackage = null;
                 mRequiredInstallerPackage = null;
@@ -2797,8 +2834,6 @@
                 setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
             }
 
-            mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
-
             // Read and update the usage of dex files.
             // Do this at the end of PM init so that all the packages have their
             // data directory reconciled.
@@ -2925,11 +2960,11 @@
         throw new RuntimeException("There must be exactly one verifier; found " + matches);
     }
 
-    private @NonNull String getRequiredSharedLibraryLPr(String libraryName) {
+    private @NonNull String getRequiredSharedLibraryLPr(String name, int version) {
         synchronized (mPackages) {
-            SharedLibraryEntry libraryEntry = mSharedLibraries.get(libraryName);
+            SharedLibraryEntry libraryEntry = getSharedLibraryEntryLPr(name, version);
             if (libraryEntry == null) {
-                throw new IllegalStateException("Missing required shared library:" + libraryName);
+                throw new IllegalStateException("Missing required shared library:" + name);
             }
             return libraryEntry.apk;
         }
@@ -3248,6 +3283,31 @@
         if (p == null) {
             return null;
         }
+        // Filter out ephemeral app metadata:
+        //   * The system/shell/root can see metadata for any app
+        //   * An installed app can see metadata for 1) other installed apps
+        //     and 2) ephemeral apps that have explicitly interacted with it
+        //   * Ephemeral apps can only see their own metadata
+        final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+        if (callingAppId != Process.SYSTEM_UID
+                && callingAppId != Process.SHELL_UID
+                && callingAppId != Process.ROOT_UID) {
+            final String ephemeralPackageName = getEphemeralPackageName(Binder.getCallingUid());
+            if (ephemeralPackageName != null) {
+                // ephemeral apps can only get information on themselves
+                if (!ephemeralPackageName.equals(p.packageName)) {
+                    return null;
+                }
+            } else {
+                if (p.applicationInfo.isEphemeralApp()) {
+                    // only get access to the ephemeral app if we've been granted access
+                    if (!mEphemeralApplicationRegistry.isEphemeralAccessGranted(
+                            userId, callingAppId, ps.appId)) {
+                        return null;
+                    }
+                }
+            }
+        }
 
         final PermissionsState permissionsState = ps.getPermissionsState();
 
@@ -3264,8 +3324,17 @@
             flags |= MATCH_ANY_USER;
         }
 
-        return PackageParser.generatePackageInfo(p, gids, flags,
+        PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags,
                 ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
+
+        if (packageInfo == null) {
+            return null;
+        }
+
+        packageInfo.packageName = packageInfo.applicationInfo.packageName =
+                resolveExternalPackageNameLPr(p);
+
+        return packageInfo;
     }
 
     @Override
@@ -3320,6 +3389,20 @@
 
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
+        return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
+                flags, userId);
+    }
+
+    @Override
+    public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
+            int flags, int userId) {
+        return getPackageInfoInternal(versionedPackage.getPackageName(),
+                // TODO: We will change version code to long, so in the new API it is long
+                (int) versionedPackage.getVersionCode(), flags, userId);
+    }
+
+    private PackageInfo getPackageInfoInternal(String packageName, int versionCode,
+            int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
@@ -3327,36 +3410,89 @@
 
         // reader
         synchronized (mPackages) {
-            // Normalize package name to hanlde renamed packages
-            packageName = normalizePackageNameLPr(packageName);
+            // Normalize package name to handle renamed packages and static libs
+            packageName = resolveInternalPackageNameLPr(packageName, versionCode);
 
             final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
-            PackageParser.Package p = null;
             if (matchFactoryOnly) {
                 final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
                 if (ps != null) {
+                    if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                        return null;
+                    }
                     return generatePackageInfo(ps, flags, userId);
                 }
             }
-            if (p == null) {
-                p = mPackages.get(packageName);
-                if (matchFactoryOnly && p != null && !isSystemApp(p)) {
-                    return null;
-                }
+
+            PackageParser.Package p = mPackages.get(packageName);
+            if (matchFactoryOnly && p != null && !isSystemApp(p)) {
+                return null;
             }
             if (DEBUG_PACKAGE_INFO)
                 Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
             if (p != null) {
+                if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
+                        Binder.getCallingUid(), userId)) {
+                    return null;
+                }
                 return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
             }
             if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                    return null;
+                }
                 return generatePackageInfo(ps, flags, userId);
             }
         }
         return null;
     }
 
+
+    private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId) {
+        // System/shell/root get to see all static libs
+        final int appId = UserHandle.getAppId(uid);
+        if (appId == Process.SYSTEM_UID || appId == Process.SHELL_UID
+                || appId == Process.ROOT_UID) {
+            return false;
+        }
+
+        // No package means no static lib as it is always on internal storage
+        if (ps == null || ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) {
+            return false;
+        }
+
+        final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(ps.pkg.staticSharedLibName,
+                ps.pkg.staticSharedLibVersion);
+        if (libEntry == null) {
+            return false;
+        }
+
+        final int resolvedUid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+        final String[] uidPackageNames = getPackagesForUid(resolvedUid);
+        if (uidPackageNames == null) {
+            return true;
+        }
+
+        for (String uidPackageName : uidPackageNames) {
+            if (ps.name.equals(uidPackageName)) {
+                return false;
+            }
+            PackageSetting uidPs = mSettings.getPackageLPr(uidPackageName);
+            if (uidPs != null) {
+                final int index = ArrayUtils.indexOf(uidPs.usesStaticLibraries,
+                        libEntry.info.getName());
+                if (index < 0) {
+                    continue;
+                }
+                if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getVersion()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
     @Override
     public String[] currentToCanonicalPackageNames(String[] names) {
         String[] out = new String[names.length];
@@ -3509,10 +3645,13 @@
     }
 
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
-            int userId) {
+            int uid, int userId) {
         if (!sUserManager.exists(userId)) return null;
         PackageSetting ps = mSettings.mPackages.get(packageName);
         if (ps != null) {
+            if (filterSharedLibPackageLPr(ps, uid, userId)) {
+                return null;
+            }
             if (ps.pkg == null) {
                 final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
                 if (pInfo != null) {
@@ -3520,8 +3659,12 @@
                 }
                 return null;
             }
-            return PackageParser.generateApplicationInfo(ps.pkg, flags,
+            ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
                     ps.readUserState(userId), userId);
+            if (ai != null) {
+                ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
+            }
+            return ai;
         }
         return null;
     }
@@ -3535,8 +3678,9 @@
 
         // writer
         synchronized (mPackages) {
-            // Normalize package name to hanlde renamed packages
-            packageName = normalizePackageNameLPr(packageName);
+            // Normalize package name to handle renamed packages and static libs
+            packageName = resolveInternalPackageNameLPr(packageName,
+                    PackageManager.VERSION_CODE_HIGHEST);
 
             PackageParser.Package p = mPackages.get(packageName);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3545,15 +3689,24 @@
             if (p != null) {
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps == null) return null;
+                if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                    return null;
+                }
                 // Note: isEnabledLP() does not apply here - always return info
-                return PackageParser.generateApplicationInfo(
+                ApplicationInfo ai = PackageParser.generateApplicationInfo(
                         p, flags, ps.readUserState(userId), userId);
+                if (ai != null) {
+                    ai.packageName = resolveExternalPackageNameLPr(p);
+                }
+                return ai;
             }
             if ("android".equals(packageName)||"system".equals(packageName)) {
                 return mAndroidApplication;
             }
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
-                return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
+                // Already generates the external package name
+                return generateApplicationInfoFromSettingsLPw(packageName,
+                        Binder.getCallingUid(), flags, userId);
             }
         }
         return null;
@@ -3576,7 +3729,7 @@
                 boolean success = true;
                 synchronized (mInstallLock) {
                     try {
-                        mInstaller.freeCache(volumeUuid, freeStorageSize);
+                        mInstaller.freeCache(volumeUuid, freeStorageSize, 0);
                     } catch (InstallerException e) {
                         Slog.w(TAG, "Couldn't clear application caches: " + e);
                         success = false;
@@ -3605,7 +3758,7 @@
                 boolean success = true;
                 synchronized (mInstallLock) {
                     try {
-                        mInstaller.freeCache(volumeUuid, freeStorageSize);
+                        mInstaller.freeCache(volumeUuid, freeStorageSize, 0);
                     } catch (InstallerException e) {
                         Slog.w(TAG, "Couldn't clear application caches: " + e);
                         success = false;
@@ -3628,7 +3781,7 @@
     void freeStorage(String volumeUuid, long freeStorageSize) throws IOException {
         synchronized (mInstallLock) {
             try {
-                mInstaller.freeCache(volumeUuid, freeStorageSize);
+                mInstaller.freeCache(volumeUuid, freeStorageSize, 0);
             } catch (InstallerException e) {
                 throw new IOException("Failed to free enough space", e);
             }
@@ -3736,6 +3889,19 @@
     }
 
     /**
+     * Update given intent when being used to request {@link ResolveInfo}.
+     */
+    private Intent updateIntentForResolve(Intent intent) {
+        if (intent.getSelector() != null) {
+            intent = intent.getSelector();
+        }
+        if (DEBUG_PREFERRED) {
+            intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+        }
+        return intent;
+    }
+
+    /**
      * Update given flags when being used to request {@link ResolveInfo}.
      */
     int updateFlagsForResolve(int flags, int userId, Object cookie) {
@@ -3826,6 +3992,113 @@
     }
 
     @Override
+    public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(int flags, int userId) {
+        if (!sUserManager.exists(userId)) return null;
+        Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
+
+        flags = updateFlagsForPackage(flags, userId, null);
+
+        final boolean canSeeStaticLibraries =
+                mContext.checkCallingOrSelfPermission(INSTALL_PACKAGES)
+                        == PERMISSION_GRANTED
+                || mContext.checkCallingOrSelfPermission(DELETE_PACKAGES)
+                        == PERMISSION_GRANTED
+                || mContext.checkCallingOrSelfPermission(REQUEST_INSTALL_PACKAGES)
+                        == PERMISSION_GRANTED
+                || mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES)
+                        == PERMISSION_GRANTED;
+
+        synchronized (mPackages) {
+            List<SharedLibraryInfo> result = null;
+
+            final int libCount = mSharedLibraries.size();
+            for (int i = 0; i < libCount; i++) {
+                SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+                if (versionedLib == null) {
+                    continue;
+                }
+
+                final int versionCount = versionedLib.size();
+                for (int j = 0; j < versionCount; j++) {
+                    SharedLibraryInfo libInfo = versionedLib.valueAt(j).info;
+                    if (!canSeeStaticLibraries && libInfo.isStatic()) {
+                        break;
+                    }
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        // TODO: We will change version code to long, so in the new API it is long
+                        PackageInfo packageInfo = getPackageInfoVersioned(
+                                libInfo.getDeclaringPackage(), flags, userId);
+                        if (packageInfo == null) {
+                            continue;
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+
+                    SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(),
+                            libInfo.getVersion(), libInfo.getType(), libInfo.getDeclaringPackage(),
+                            getPackagesUsingSharedLibraryLPr(libInfo, flags, userId));
+
+                    if (result == null) {
+                        result = new ArrayList<>();
+                    }
+                    result.add(resLibInfo);
+                }
+            }
+
+            return result != null ? new ParceledListSlice<>(result) : null;
+        }
+    }
+
+    private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
+            SharedLibraryInfo libInfo, int flags, int userId) {
+        List<VersionedPackage> versionedPackages = null;
+        final int packageCount = mSettings.mPackages.size();
+        for (int i = 0; i < packageCount; i++) {
+            PackageSetting ps = mSettings.mPackages.valueAt(i);
+
+            if (ps == null) {
+                continue;
+            }
+
+            if (!ps.getUserState().get(userId).isAvailable(flags)) {
+                continue;
+            }
+
+            final String libName = libInfo.getName();
+            if (libInfo.isStatic()) {
+                final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
+                if (libIdx < 0) {
+                    continue;
+                }
+                if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getVersion()) {
+                    continue;
+                }
+                if (versionedPackages == null) {
+                    versionedPackages = new ArrayList<>();
+                }
+                // If the dependent is a static shared lib, use the public package name
+                String dependentPackageName = ps.name;
+                if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) {
+                    dependentPackageName = ps.pkg.manifestPackageName;
+                }
+                versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode));
+            } else if (ps.pkg != null) {
+                if (ArrayUtils.contains(ps.pkg.usesLibraries, libName)
+                        || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) {
+                    if (versionedPackages == null) {
+                        versionedPackages = new ArrayList<>();
+                    }
+                    versionedPackages.add(new VersionedPackage(ps.name, ps.versionCode));
+                }
+            }
+        }
+
+        return versionedPackages;
+    }
+
+    @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
@@ -3867,17 +4140,44 @@
 
     @Override
     public String[] getSystemSharedLibraryNames() {
-        Set<String> libSet;
         synchronized (mPackages) {
-            libSet = mSharedLibraries.keySet();
-            int size = libSet.size();
-            if (size > 0) {
-                String[] libs = new String[size];
-                libSet.toArray(libs);
-                return libs;
+            Set<String> libs = null;
+            final int libCount = mSharedLibraries.size();
+            for (int i = 0; i < libCount; i++) {
+                SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+                if (versionedLib == null) {
+                    continue;
+                }
+                final int versionCount = versionedLib.size();
+                for (int j = 0; j < versionCount; j++) {
+                    SharedLibraryEntry libEntry = versionedLib.valueAt(j);
+                    if (!libEntry.info.isStatic()) {
+                        if (libs == null) {
+                            libs = new ArraySet<>();
+                        }
+                        libs.add(libEntry.info.getName());
+                        break;
+                    }
+                    PackageSetting ps = mSettings.getPackageLPr(libEntry.apk);
+                    if (ps != null && !filterSharedLibPackageLPr(ps, Binder.getCallingUid(),
+                            UserHandle.getUserId(Binder.getCallingUid()))) {
+                        if (libs == null) {
+                            libs = new ArraySet<>();
+                        }
+                        libs.add(libEntry.info.getName());
+                        break;
+                    }
+                }
             }
+
+            if (libs != null) {
+                String[] libsArray = new String[libs.size()];
+                libs.toArray(libsArray);
+                return libsArray;
+            }
+
+            return null;
         }
-        return null;
     }
 
     @Override
@@ -4989,7 +5289,9 @@
                 return res;
             } else if (obj instanceof PackageSetting) {
                 final PackageSetting ps = (PackageSetting) obj;
-                return new String[] { ps.name };
+                if (ps.getInstalled(userId)) {
+                    return new String[]{ps.name};
+                }
             }
         }
         return null;
@@ -5119,6 +5421,26 @@
     }
 
     @Override
+    public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+        if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) {
+            throw new SecurityException(
+                    "findPersistentPreferredActivity can only be run by the system");
+        }
+        if (!sUserManager.exists(userId)) {
+            return null;
+        }
+        intent = updateIntentForResolve(intent);
+        final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
+        final int flags = updateFlagsForResolve(0, userId, intent);
+        final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
+                userId);
+        synchronized (mPackages) {
+            return findPersistentPreferredActivityLP(intent, resolvedType, flags, query, false,
+                    userId);
+        }
+    }
+
+    @Override
     public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
             IntentFilter filter, int match, ComponentName activity) {
         final int userId = UserHandle.getCallingUserId();
@@ -5384,13 +5706,9 @@
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(flags, userId, intent);
+        intent = updateIntentForResolve(intent);
         // writer
         synchronized (mPackages) {
-            if (intent.getSelector() != null) {
-                intent = intent.getSelector();
-            }
-            if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
-
             // Try to find a matching persistent preferred activity.
             ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
                     debug, userId);
@@ -5956,7 +6274,7 @@
                     int status = (int)(packedStatus >> 32);
                     int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
                     if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
-                        if (DEBUG_DOMAIN_VERIFICATION) {
+                        if (DEBUG_DOMAIN_VERIFICATION || debug) {
                             Slog.i(TAG, "  + always: " + info.activityInfo.packageName
                                     + " : linkgen=" + linkGeneration);
                         }
@@ -5965,18 +6283,18 @@
                         info.preferredOrder = linkGeneration;
                         alwaysList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
-                        if (DEBUG_DOMAIN_VERIFICATION) {
+                        if (DEBUG_DOMAIN_VERIFICATION || debug) {
                             Slog.i(TAG, "  + never: " + info.activityInfo.packageName);
                         }
                         neverList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
-                        if (DEBUG_DOMAIN_VERIFICATION) {
+                        if (DEBUG_DOMAIN_VERIFICATION || debug) {
                             Slog.i(TAG, "  + always-ask: " + info.activityInfo.packageName);
                         }
                         alwaysAskList.add(info);
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED ||
                             status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) {
-                        if (DEBUG_DOMAIN_VERIFICATION) {
+                        if (DEBUG_DOMAIN_VERIFICATION || debug) {
                             Slog.i(TAG, "  + ask: " + info.activityInfo.packageName);
                         }
                         undefinedList.add(info);
@@ -6541,30 +6859,32 @@
         synchronized (mPackages) {
             ArrayList<PackageInfo> list;
             if (listUninstalled) {
-                list = new ArrayList<PackageInfo>(mSettings.mPackages.size());
+                list = new ArrayList<>(mSettings.mPackages.size());
                 for (PackageSetting ps : mSettings.mPackages.values()) {
-                    final PackageInfo pi;
-                    if (ps.pkg != null) {
-                        pi = generatePackageInfo(ps, flags, userId);
-                    } else {
-                        pi = generatePackageInfo(ps, flags, userId);
+                    if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                        continue;
                     }
+                    final PackageInfo pi = generatePackageInfo(ps, flags, userId);
                     if (pi != null) {
                         list.add(pi);
                     }
                 }
             } else {
-                list = new ArrayList<PackageInfo>(mPackages.size());
+                list = new ArrayList<>(mPackages.size());
                 for (PackageParser.Package p : mPackages.values()) {
-                    final PackageInfo pi =
-                            generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
+                    if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
+                            Binder.getCallingUid(), userId)) {
+                        continue;
+                    }
+                    final PackageInfo pi = generatePackageInfo((PackageSetting)
+                            p.mExtras, flags, userId);
                     if (pi != null) {
                         list.add(pi);
                     }
                 }
             }
 
-            return new ParceledListSlice<PackageInfo>(list);
+            return new ParceledListSlice<>(list);
         }
     }
 
@@ -6584,12 +6904,8 @@
         if (numMatch == 0) {
             return;
         }
-        final PackageInfo pi;
-        if (ps.pkg != null) {
-            pi = generatePackageInfo(ps, flags, userId);
-        } else {
-            pi = generatePackageInfo(ps, flags, userId);
-        }
+        final PackageInfo pi = generatePackageInfo(ps, flags, userId);
+
         // The above might return null in cases of uninstalled apps or install-state
         // skew across users/profiles.
         if (pi != null) {
@@ -6654,7 +6970,7 @@
         synchronized (mPackages) {
             ArrayList<ApplicationInfo> list;
             if (listUninstalled) {
-                list = new ArrayList<ApplicationInfo>(mSettings.mPackages.size());
+                list = new ArrayList<>(mSettings.mPackages.size());
                 for (PackageSetting ps : mSettings.mPackages.values()) {
                     ApplicationInfo ai;
                     int effectiveFlags = flags;
@@ -6662,30 +6978,43 @@
                         effectiveFlags |= PackageManager.MATCH_ANY_USER;
                     }
                     if (ps.pkg != null) {
+                        if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                            continue;
+                        }
                         ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
                                 ps.readUserState(userId), userId);
+                        if (ai != null) {
+                            ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
+                        }
                     } else {
-                        ai = generateApplicationInfoFromSettingsLPw(ps.name, effectiveFlags,
-                                userId);
+                        // Shared lib filtering done in generateApplicationInfoFromSettingsLPw
+                        // and already converts to externally visible package name
+                        ai = generateApplicationInfoFromSettingsLPw(ps.name,
+                                Binder.getCallingUid(), effectiveFlags, userId);
                     }
                     if (ai != null) {
                         list.add(ai);
                     }
                 }
             } else {
-                list = new ArrayList<ApplicationInfo>(mPackages.size());
+                list = new ArrayList<>(mPackages.size());
                 for (PackageParser.Package p : mPackages.values()) {
                     if (p.mExtras != null) {
+                        PackageSetting ps = (PackageSetting) p.mExtras;
+                        if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId)) {
+                            continue;
+                        }
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
-                                ((PackageSetting)p.mExtras).readUserState(userId), userId);
+                                ps.readUserState(userId), userId);
                         if (ai != null) {
+                            ai.packageName = resolveExternalPackageNameLPr(p);
                             list.add(ai);
                         }
                     }
                 }
             }
 
-            return new ParceledListSlice<ApplicationInfo>(list);
+            return new ParceledListSlice<>(list);
         }
     }
 
@@ -6775,6 +7104,7 @@
 
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplicationIcon");
+
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "getEphemeralApplicationIcon");
@@ -7051,9 +7381,15 @@
             int errorCode = PackageManager.INSTALL_SUCCEEDED;
 
             if (throwable == null) {
+                // Static shared libraries have synthetic package names
+                if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) {
+                    renameStaticSharedLibraryPackage(parseResult.pkg);
+                }
                 try {
-                    scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
-                            currentTime, null);
+                    if (errorCode == PackageManager.INSTALL_SUCCEEDED) {
+                        scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
+                                currentTime, null);
+                    }
                 } catch (PackageManagerException e) {
                     errorCode = e.error;
                     Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
@@ -7207,6 +7543,11 @@
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
+        // Static shared libraries have synthetic package names
+        if (pkg.applicationInfo.isStaticSharedLibrary()) {
+            renameStaticSharedLibraryPackage(pkg);
+        }
+
         return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
     }
 
@@ -7509,6 +7850,12 @@
         return scannedPkg;
     }
 
+    private void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+        // Derive the new package synthetic package name
+        pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
+                + pkg.staticSharedLibVersion);
+    }
+
     private static String fixProcessName(String defProcessName,
             String processName) {
         if (processName == null) {
@@ -7864,8 +8211,9 @@
                 targetCompilerFilter, getOrCreateCompilerPackageStats(p));
     }
 
-    Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
-        if (p.usesLibraries != null || p.usesOptionalLibraries != null) {
+    List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
+        if (p.usesLibraries != null || p.usesOptionalLibraries != null
+                || p.usesStaticLibraries != null) {
             ArrayList<PackageParser.Package> retValue = new ArrayList<>();
             Set<String> collectedNames = new HashSet<>();
             findSharedNonSystemLibrariesRecursive(p, retValue, collectedNames);
@@ -7879,37 +8227,74 @@
     }
 
     private void findSharedNonSystemLibrariesRecursive(PackageParser.Package p,
-            Collection<PackageParser.Package> collected, Set<String> collectedNames) {
+            ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
         if (!collectedNames.contains(p.packageName)) {
             collectedNames.add(p.packageName);
             collected.add(p);
 
             if (p.usesLibraries != null) {
-                findSharedNonSystemLibrariesRecursive(p.usesLibraries, collected, collectedNames);
+                findSharedNonSystemLibrariesRecursive(p.usesLibraries,
+                        null, collected, collectedNames);
             }
             if (p.usesOptionalLibraries != null) {
-                findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries, collected,
-                        collectedNames);
+                findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries,
+                        null, collected, collectedNames);
+            }
+            if (p.usesStaticLibraries != null) {
+                findSharedNonSystemLibrariesRecursive(p.usesStaticLibraries,
+                        p.usesStaticLibrariesVersions, collected, collectedNames);
             }
         }
     }
 
-    private void findSharedNonSystemLibrariesRecursive(Collection<String> libs,
-            Collection<PackageParser.Package> collected, Set<String> collectedNames) {
-        for (String libName : libs) {
-            PackageParser.Package libPkg = findSharedNonSystemLibrary(libName);
+    private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, int[] versions,
+            ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
+        final int libNameCount = libs.size();
+        for (int i = 0; i < libNameCount; i++) {
+            String libName = libs.get(i);
+            int version = (versions != null && versions.length == libNameCount)
+                    ? versions[i] : PackageManager.VERSION_CODE_HIGHEST;
+            PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version);
             if (libPkg != null) {
                 findSharedNonSystemLibrariesRecursive(libPkg, collected, collectedNames);
             }
         }
     }
 
-    private PackageParser.Package findSharedNonSystemLibrary(String libName) {
+    private PackageParser.Package findSharedNonSystemLibrary(String name, int version) {
         synchronized (mPackages) {
-            PackageManagerService.SharedLibraryEntry lib = mSharedLibraries.get(libName);
-            if (lib != null && lib.apk != null) {
-                return mPackages.get(lib.apk);
+            SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(name, version);
+            if (libEntry != null) {
+                return mPackages.get(libEntry.apk);
             }
+            return null;
+        }
+    }
+
+    private SharedLibraryEntry getSharedLibraryEntryLPr(String name, int version) {
+        SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+        if (versionedLib == null) {
+            return null;
+        }
+        return versionedLib.get(version);
+    }
+
+    private SharedLibraryEntry getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
+        SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+                pkg.staticSharedLibName);
+        if (versionedLib == null) {
+            return null;
+        }
+        int previousLibVersion = -1;
+        final int versionCount = versionedLib.size();
+        for (int i = 0; i < versionCount; i++) {
+            final int libVersion = versionedLib.keyAt(i);
+            if (libVersion < pkg.staticSharedLibVersion) {
+                previousLibVersion = Math.max(previousLibVersion, libVersion);
+            }
+        }
+        if (previousLibVersion >= 0) {
+            return versionedLib.get(previousLibVersion);
         }
         return null;
     }
@@ -8203,36 +8588,84 @@
 
     private void updateSharedLibrariesLPr(PackageParser.Package pkg,
             PackageParser.Package changingLib) throws PackageManagerException {
-        if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
-            final ArraySet<String> usesLibraryFiles = new ArraySet<>();
-            int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0;
-            for (int i=0; i<N; i++) {
-                final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i));
-                if (file == null) {
+        if (pkg == null) {
+            return;
+        }
+        ArraySet<String> usesLibraryFiles = null;
+        if (pkg.usesLibraries != null) {
+            usesLibraryFiles = addSharedLibrariesLPw(pkg.usesLibraries,
+                    null, null, pkg.packageName, changingLib, true, null);
+        }
+        if (pkg.usesStaticLibraries != null) {
+            usesLibraryFiles = addSharedLibrariesLPw(pkg.usesStaticLibraries,
+                    pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests,
+                    pkg.packageName, changingLib, true, usesLibraryFiles);
+        }
+        if (pkg.usesOptionalLibraries != null) {
+            usesLibraryFiles = addSharedLibrariesLPw(pkg.usesOptionalLibraries,
+                    null, null, pkg.packageName, changingLib, false, usesLibraryFiles);
+        }
+        if (!ArrayUtils.isEmpty(usesLibraryFiles)) {
+            pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
+        } else {
+            pkg.usesLibraryFiles = null;
+        }
+    }
+
+    private ArraySet<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries,
+            @Nullable int[] requiredVersions, @Nullable String[] requiredCertDigests,
+            @NonNull String packageName, @Nullable PackageParser.Package changingLib,
+            boolean required, @Nullable ArraySet<String> outUsedLibraries)
+            throws PackageManagerException {
+        final int libCount = requestedLibraries.size();
+        for (int i = 0; i < libCount; i++) {
+            final String libName = requestedLibraries.get(i);
+            final int libVersion = requiredVersions != null ? requiredVersions[i]
+                    : SharedLibraryInfo.VERSION_UNDEFINED;
+            final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(libName, libVersion);
+            if (libEntry == null) {
+                if (required) {
                     throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
-                            "Package " + pkg.packageName + " requires unavailable shared library "
-                            + pkg.usesLibraries.get(i) + "; failing!");
-                }
-                addSharedLibraryLPr(usesLibraryFiles, file, changingLib);
-            }
-            N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
-            for (int i=0; i<N; i++) {
-                final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesOptionalLibraries.get(i));
-                if (file == null) {
-                    Slog.w(TAG, "Package " + pkg.packageName
-                            + " desires unavailable shared library "
-                            + pkg.usesOptionalLibraries.get(i) + "; ignoring!");
+                            "Package " + packageName + " requires unavailable shared library "
+                                    + libName + "; failing!");
                 } else {
-                    addSharedLibraryLPr(usesLibraryFiles, file, changingLib);
+                    Slog.w(TAG, "Package " + packageName
+                            + " desires unavailable shared library "
+                            + libName + "; ignoring!");
                 }
-            }
-            N = usesLibraryFiles.size();
-            if (N > 0) {
-                pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]);
             } else {
-                pkg.usesLibraryFiles = null;
+                if (requiredVersions != null && requiredCertDigests != null) {
+                    if (libEntry.info.getVersion() != requiredVersions[i]) {
+                        throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
+                            "Package " + packageName + " requires unavailable static shared"
+                                    + " library " + libName + " version "
+                                    + libEntry.info.getVersion() + "; failing!");
+                    }
+
+                    PackageParser.Package libPkg = mPackages.get(libEntry.apk);
+                    if (libPkg == null) {
+                        throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
+                                "Package " + packageName + " requires unavailable static shared"
+                                        + " library; failing!");
+                    }
+
+                    String expectedCertDigest = requiredCertDigests[i];
+                    String libCertDigest = PackageUtils.computeCertSha256Digest(
+                                libPkg.mSignatures[0]);
+                    if (!libCertDigest.equalsIgnoreCase(expectedCertDigest)) {
+                        throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
+                                "Package " + packageName + " requires differently signed" +
+                                        " static shared library; failing!");
+                    }
+                }
+
+                if (outUsedLibraries == null) {
+                    outUsedLibraries = new ArraySet<>();
+                }
+                addSharedLibraryLPr(outUsedLibraries, libEntry, changingLib);
             }
         }
+        return outUsedLibraries;
     }
 
     private static boolean hasString(List<String> list, List<String> which) {
@@ -8249,31 +8682,36 @@
         return false;
     }
 
-    private void updateAllSharedLibrariesLPw() {
-        for (PackageParser.Package pkg : mPackages.values()) {
-            try {
-                updateSharedLibrariesLPr(pkg, null);
-            } catch (PackageManagerException e) {
-                Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
-            }
-        }
-    }
-
     private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
             PackageParser.Package changingPkg) {
         ArrayList<PackageParser.Package> res = null;
         for (PackageParser.Package pkg : mPackages.values()) {
-            if (hasString(pkg.usesLibraries, changingPkg.libraryNames)
-                    || hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)) {
-                if (res == null) {
-                    res = new ArrayList<PackageParser.Package>();
+            if (changingPkg != null
+                    && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
+                    && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
+                    && !ArrayUtils.contains(pkg.usesStaticLibraries,
+                            changingPkg.staticSharedLibName)) {
+                return null;
+            }
+            if (res == null) {
+                res = new ArrayList<>();
+            }
+            res.add(pkg);
+            try {
+                updateSharedLibrariesLPr(pkg, changingPkg);
+            } catch (PackageManagerException e) {
+                // If a system app update or an app and a required lib missing we
+                // delete the package and for updated system apps keep the data as
+                // it is better for the user to reinstall than to be in an limbo
+                // state. Also libs disappearing under an app should never happen
+                // - just in case.
+                if (!pkg.isSystemApp() || pkg.isUpdatedSystemApp()) {
+                    final int flags = pkg.isUpdatedSystemApp()
+                            ? PackageManager.DELETE_KEEP_DATA : 0;
+                    deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+                            flags , null, true, null);
                 }
-                res.add(pkg);
-                try {
-                    updateSharedLibrariesLPr(pkg, changingPkg);
-                } catch (PackageManagerException e) {
-                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
-                }
+                Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
             }
         }
         return res;
@@ -8531,9 +8969,17 @@
                     pkgSetting == null ? null : new PackageSetting(pkgSetting);
             final PackageSetting disabledPkgSetting =
                     mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+
+            String[] usesStaticLibraries = null;
+            if (pkg.usesStaticLibraries != null) {
+                usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
+                pkg.usesStaticLibraries.toArray(usesStaticLibraries);
+            }
+
             if (pkgSetting == null) {
                 final String parentPackageName = (pkg.parentPackage != null)
                         ? pkg.parentPackage.packageName : null;
+
                 // REMOVE SharedUserSetting from method; update in a separate call
                 pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
                         disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
@@ -8541,7 +8987,8 @@
                         pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
                         pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
                         true /*allowInstall*/, parentPackageName, pkg.getChildPackageNames(),
-                        UserManagerService.getInstance());
+                        UserManagerService.getInstance(), usesStaticLibraries,
+                        pkg.usesStaticLibrariesVersions);
                 // SIDE EFFECTS; updates system state; move elsewhere
                 if (origPackage != null) {
                     mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name);
@@ -8557,7 +9004,8 @@
                         pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
                         pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
                         pkg.applicationInfo.privateFlags, pkg.getChildPackageNames(),
-                        UserManagerService.getInstance());
+                        UserManagerService.getInstance(), usesStaticLibraries,
+                        pkg.usesStaticLibrariesVersions);
             }
             // SIDE EFFECTS; persists system state to files on disk; move elsewhere
             mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
@@ -8594,12 +9042,15 @@
                 pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
             }
 
-            if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+            if ((scanFlags & SCAN_BOOTING) == 0
+                    && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
                 // Check all shared libraries and map to their actual file path.
                 // We only do this here for apps not on a system dir, because those
                 // are the only ones that can fail an install due to this.  We
                 // will take care of the system apps by updating all of their
-                // library paths after the scan is done.
+                // library paths after the scan is done. Also during the initial
+                // scan don't update any libs as we do this wholesale after all
+                // apps are scanned to avoid dependency based scanning.
                 updateSharedLibrariesLPr(pkg, null);
             }
 
@@ -8609,8 +9060,22 @@
 
             pkg.applicationInfo.uid = pkgSetting.appId;
             pkg.mExtras = pkgSetting;
-            if (shouldCheckUpgradeKeySetLP(pkgSetting, scanFlags)) {
-                if (checkUpgradeKeySetLP(pkgSetting, pkg)) {
+
+
+            // Static shared libs have same package with different versions where
+            // we internally use a synthetic package name to allow multiple versions
+            // of the same package, therefore we need to compare signatures against
+            // the package setting for the latest library version.
+            PackageSetting signatureCheckPs = pkgSetting;
+            if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
+                if (libraryEntry != null) {
+                    signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
+                }
+            }
+
+            if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
+                if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
                     // We just determined the app is signed correctly, so bring
                     // over the latest parsed certs.
                     pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -8629,7 +9094,7 @@
             } else {
                 try {
                     // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
-                    verifySignaturesLP(pkgSetting, pkg);
+                    verifySignaturesLP(signatureCheckPs, pkg);
                     // We just determined the app is signed correctly, so bring
                     // over the latest parsed certs.
                     pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -8645,8 +9110,8 @@
                     // What this means is that you can't change the signatures
                     // associated with an overall shared user, which doesn't seem all
                     // that unreasonable.
-                    if (pkgSetting.sharedUser != null) {
-                        if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
+                    if (signatureCheckPs.sharedUser != null) {
+                        if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures,
                                 pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
                             throw new PackageManagerException(
                                     INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
@@ -8830,6 +9295,10 @@
             // Modify state for the given package setting
             commitPackageSettings(pkg, pkgSetting, user, scanFlags,
                     (policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
+            if (isEphemeral(pkg)) {
+                final int userId = user == null ? 0 : user.getIdentifier();
+                mEphemeralApplicationRegistry.addEphemeralAppLPw(userId, pkgSetting.appId);
+            }
         }
         return pkg;
     }
@@ -8883,7 +9352,7 @@
     }
 
     /**
-     * Asserts the parsed package is valid according to teh given policy. If the
+     * Asserts the parsed package is valid according to the given policy. If the
      * package is invalid, for whatever reason, throws {@link PackgeManagerException}.
      * <p>
      * Implementation detail: This method must NOT have any side effects. It would
@@ -8922,13 +9391,134 @@
             }
 
             // A package name must be unique; don't allow duplicates
-            if (mPackages.containsKey(pkg.packageName)
-                    || mSharedLibraries.containsKey(pkg.packageName)) {
+            if (mPackages.containsKey(pkg.packageName)) {
                 throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                         "Application package " + pkg.packageName
                         + " already installed.  Skipping duplicate.");
             }
 
+            if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                // Static libs have a synthetic package name containing the version
+                // but we still want the base name to be unique.
+                if (mPackages.containsKey(pkg.manifestPackageName)) {
+                    throw new PackageManagerException(
+                            "Duplicate static shared lib provider package");
+                }
+
+                // Static shared libraries should have at least O target SDK
+                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+                    throw new PackageManagerException(
+                            "Packages declaring static-shared libs must target O SDK or higher");
+                }
+
+                // Package declaring static a shared lib cannot be ephemeral
+                if (pkg.applicationInfo.isEphemeralApp()) {
+                    throw new PackageManagerException(
+                            "Packages declaring static-shared libs cannot be ephemeral");
+                }
+
+                // Package declaring static a shared lib cannot be renamed since the package
+                // name is synthetic and apps can't code around package manager internals.
+                if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) {
+                    throw new PackageManagerException(
+                            "Packages declaring static-shared libs cannot be renamed");
+                }
+
+                // Package declaring static a shared lib cannot declare child packages
+                if (!ArrayUtils.isEmpty(pkg.childPackages)) {
+                    throw new PackageManagerException(
+                            "Packages declaring static-shared libs cannot have child packages");
+                }
+
+                // Package declaring static a shared lib cannot declare dynamic libs
+                if (!ArrayUtils.isEmpty(pkg.libraryNames)) {
+                    throw new PackageManagerException(
+                            "Packages declaring static-shared libs cannot declare dynamic libs");
+                }
+
+                // Package declaring static a shared lib cannot declare shared users
+                if (pkg.mSharedUserId != null) {
+                    throw new PackageManagerException(
+                            "Packages declaring static-shared libs cannot declare shared users");
+                }
+
+                // Static shared libs cannot declare activities
+                if (!pkg.activities.isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare activities");
+                }
+
+                // Static shared libs cannot declare services
+                if (!pkg.services.isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare services");
+                }
+
+                // Static shared libs cannot declare providers
+                if (!pkg.providers.isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare content providers");
+                }
+
+                // Static shared libs cannot declare receivers
+                if (!pkg.receivers.isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare broadcast receivers");
+                }
+
+                // Static shared libs cannot declare permission groups
+                if (!pkg.permissionGroups.isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare permission groups");
+                }
+
+                // Static shared libs cannot declare permissions
+                if (!pkg.permissions.isEmpty()) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare permissions");
+                }
+
+                // Static shared libs cannot declare protected broadcasts
+                if (pkg.protectedBroadcasts != null) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot declare protected broadcasts");
+                }
+
+                // Static shared libs cannot be overlay targets
+                if (pkg.mOverlayTarget != null) {
+                    throw new PackageManagerException(
+                            "Static shared libs cannot be overlay targets");
+                }
+
+                // The version codes must be ordered as lib versions
+                int minVersionCode = Integer.MIN_VALUE;
+                int maxVersionCode = Integer.MAX_VALUE;
+
+                SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+                        pkg.staticSharedLibName);
+                if (versionedLib != null) {
+                    final int versionCount = versionedLib.size();
+                    for (int i = 0; i < versionCount; i++) {
+                        SharedLibraryInfo libInfo = versionedLib.valueAt(i).info;
+                        // TODO: We will change version code to long, so in the new API it is long
+                        final int libVersionCode = (int) libInfo.getDeclaringPackage()
+                                .getVersionCode();
+                        if (libInfo.getVersion() <  pkg.staticSharedLibVersion) {
+                            minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
+                        } else if (libInfo.getVersion() >  pkg.staticSharedLibVersion) {
+                            maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
+                        } else {
+                            minVersionCode = maxVersionCode = libVersionCode;
+                            break;
+                        }
+                    }
+                }
+                if (pkg.mVersionCode < minVersionCode || pkg.mVersionCode > maxVersionCode) {
+                    throw new PackageManagerException("Static shared"
+                            + " lib version codes must be ordered as lib versions");
+                }
+            }
+
             // Only privileged apps and updated privileged apps can add child packages.
             if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
                 if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) {
@@ -9009,6 +9599,45 @@
         }
     }
 
+    private boolean addSharedLibraryLPw(String path, String apk, String name, int version,
+            int type, String declaringPackageName, int declaringVersionCode) {
+        SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+        if (versionedLib == null) {
+            versionedLib = new SparseArray<>();
+            mSharedLibraries.put(name, versionedLib);
+            if (type == SharedLibraryInfo.TYPE_STATIC) {
+                mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
+            }
+        } else if (versionedLib.indexOfKey(version) >= 0) {
+            return false;
+        }
+        SharedLibraryEntry libEntry = new SharedLibraryEntry(path, apk, name,
+                version, type, declaringPackageName, declaringVersionCode);
+        versionedLib.put(version, libEntry);
+        return true;
+    }
+
+    private boolean removeSharedLibraryLPw(String name, int version) {
+        SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+        if (versionedLib == null) {
+            return false;
+        }
+        final int libIdx = versionedLib.indexOfKey(version);
+        if (libIdx < 0) {
+            return false;
+        }
+        SharedLibraryEntry libEntry = versionedLib.valueAt(libIdx);
+        versionedLib.remove(version);
+        if (versionedLib.size() <= 0) {
+            mSharedLibraries.remove(name);
+            if (libEntry.info.getType() == SharedLibraryInfo.TYPE_STATIC) {
+                mStaticLibsByDeclaringPackage.remove(libEntry.info.getDeclaringPackage()
+                        .getPackageName());
+            }
+        }
+        return true;
+    }
+
     /**
      * Adds a scanned package to the system. When this method is finished, the package will
      * be available for query, resolution, etc...
@@ -9061,10 +9690,30 @@
         ArrayList<PackageParser.Package> clientLibPkgs = null;
         // writer
         synchronized (mPackages) {
-            if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-                // Only system apps can add new shared libraries.
+            boolean hasStaticSharedLibs = false;
+
+            // Any app can add new static shared libraries
+            if (pkg.staticSharedLibName != null) {
+                // Static shared libs don't allow renaming as they have synthetic package
+                // names to allow install of multiple versions, so use name from manifest.
+                if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName,
+                        pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC,
+                        pkg.manifestPackageName, pkg.mVersionCode)) {
+                    hasStaticSharedLibs = true;
+                } else {
+                    Slog.w(TAG, "Package " + pkg.packageName + " library "
+                                + pkg.staticSharedLibName + " already exists; skipping");
+                }
+                // Static shared libs cannot be updated once installed since they
+                // use synthetic package name which includes the version code, so
+                // not need to update other packages's shared lib dependencies.
+            }
+
+            if (!hasStaticSharedLibs
+                    && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                // Only system apps can add new dynamic shared libraries.
                 if (pkg.libraryNames != null) {
-                    for (int i=0; i<pkg.libraryNames.size(); i++) {
+                    for (int i = 0; i < pkg.libraryNames.size(); i++) {
                         String name = pkg.libraryNames.get(i);
                         boolean allowed = false;
                         if (pkg.isUpdatedSystemApp()) {
@@ -9081,7 +9730,7 @@
                             final PackageSetting sysPs = mSettings
                                     .getDisabledSystemPkgLPr(pkg.packageName);
                             if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) {
-                                for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) {
+                                for (int j = 0; j < sysPs.pkg.libraryNames.size(); j++) {
                                     if (name.equals(sysPs.pkg.libraryNames.get(j))) {
                                         allowed = true;
                                         break;
@@ -9092,9 +9741,10 @@
                             allowed = true;
                         }
                         if (allowed) {
-                            if (!mSharedLibraries.containsKey(name)) {
-                                mSharedLibraries.put(name, new SharedLibraryEntry(null, pkg.packageName));
-                            } else if (!name.equals(pkg.packageName)) {
+                            if (!addSharedLibraryLPw(null, pkg.packageName, name,
+                                    SharedLibraryInfo.VERSION_UNDEFINED,
+                                    SharedLibraryInfo.TYPE_DYNAMIC,
+                                    pkg.packageName, pkg.mVersionCode)) {
                                 Slog.w(TAG, "Package " + pkg.packageName + " library "
                                         + name + " already exists; skipping");
                             }
@@ -9103,6 +9753,7 @@
                                     + name + " that is not declared on system image; skipping");
                         }
                     }
+
                     if ((scanFlags & SCAN_BOOTING) == 0) {
                         // If we are not booting, we need to update any applications
                         // that are clients of our shared library.  If we are booting,
@@ -10316,11 +10967,9 @@
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
             // Only system apps can hold shared libraries.
             if (pkg.libraryNames != null) {
-                for (i=0; i<pkg.libraryNames.size(); i++) {
+                for (i = 0; i < pkg.libraryNames.size(); i++) {
                     String name = pkg.libraryNames.get(i);
-                    SharedLibraryEntry cur = mSharedLibraries.get(name);
-                    if (cur != null && cur.apk != null && cur.apk.equals(pkg.packageName)) {
-                        mSharedLibraries.remove(name);
+                    if (removeSharedLibraryLPw(name, 0)) {
                         if (DEBUG_REMOVE && chatty) {
                             if (r == null) {
                                 r = new StringBuilder(256);
@@ -10333,6 +10982,23 @@
                 }
             }
         }
+
+        r = null;
+
+        // Any package can hold static shared libraries.
+        if (pkg.staticSharedLibName != null) {
+            if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) {
+                if (DEBUG_REMOVE && chatty) {
+                    if (r == null) {
+                        r = new StringBuilder(256);
+                    } else {
+                        r.append(' ');
+                    }
+                    r.append(pkg.staticSharedLibName);
+                }
+            }
+        }
+
         if (r != null) {
             if (DEBUG_REMOVE) Log.d(TAG, "  Libraries: " + r);
         }
@@ -12134,7 +12800,7 @@
         IActivityManager am = ActivityManager.getService();
         if (am != null) {
             try {
-                am.startService(null, intent, null, mContext.getOpPackageName(),
+                am.startService(null, intent, null, -1, null, mContext.getOpPackageName(),
                         UserHandle.USER_SYSTEM);
             } catch (RemoteException e) {
             }
@@ -12208,6 +12874,67 @@
         mHandler.sendMessage(msg);
     }
 
+
+    /**
+     * Ensure that the install reason matches what we know about the package installer (e.g. whether
+     * it is acting on behalf on an enterprise or the user).
+     *
+     * Note that the ordering of the conditionals in this method is important. The checks we perform
+     * are as follows, in this order:
+     *
+     * 1) If the install is being performed by a system app, we can trust the app to have set the
+     *    install reason correctly. Thus, we pass through the install reason unchanged, no matter
+     *    what it is.
+     * 2) If the install is being performed by a device or profile owner app, the install reason
+     *    should be enterprise policy. However, we cannot be sure that the device or profile owner
+     *    set the install reason correctly. If the app targets an older SDK version where install
+     *    reasons did not exist yet, or if the app author simply forgot, the install reason may be
+     *    unset or wrong. Thus, we force the install reason to be enterprise policy.
+     * 3) In all other cases, the install is being performed by a regular app that is neither part
+     *    of the system nor a device or profile owner. We have no reason to believe that this app is
+     *    acting on behalf of the enterprise admin. Thus, we check whether the install reason was
+     *    set to enterprise policy and if so, change it to unknown instead.
+     */
+    private int fixUpInstallReason(String installerPackageName, int installerUid,
+            int installReason) {
+        if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+                == PERMISSION_GRANTED) {
+            // If the install is being performed by a system app, we trust that app to have set the
+            // install reason correctly.
+            return installReason;
+        }
+
+        final IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
+            ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+        if (dpm != null) {
+            ComponentName owner = null;
+            try {
+                owner = dpm.getDeviceOwnerComponent(true /* callingUserOnly */);
+                if (owner == null) {
+                    owner = dpm.getProfileOwner(UserHandle.getUserId(installerUid));
+                }
+            } catch (RemoteException e) {
+            }
+            if (owner != null && owner.getPackageName().equals(installerPackageName)) {
+                // If the install is being performed by a device or profile owner, the install
+                // reason should be enterprise policy.
+                return PackageManager.INSTALL_REASON_POLICY;
+            }
+        }
+
+        if (installReason == PackageManager.INSTALL_REASON_POLICY) {
+            // If the install is being performed by a regular app (i.e. neither system app nor
+            // device or profile owner), we have no reason to believe that the app is acting on
+            // behalf of an enterprise. If the app set the install reason to enterprise policy,
+            // change it to unknown instead.
+            return PackageManager.INSTALL_REASON_UNKNOWN;
+        }
+
+        // If the install is being performed by a regular app and the install reason was set to any
+        // value but enterprise policy, leave the install reason unchanged.
+        return installReason;
+    }
+
     void installStage(String packageName, File stagedDir, String stagedCid,
             IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
             String installerPackageName, int installerUid, UserHandle user,
@@ -12229,10 +12956,12 @@
         }
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
+        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
+                sessionParams.installReason);
         final InstallParams params = new InstallParams(origin, null, observer,
                 sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                 verificationInfo, user, sessionParams.abiOverride,
-                sessionParams.grantedRuntimePermissions, certificates, sessionParams.installReason);
+                sessionParams.grantedRuntimePermissions, certificates, installReason);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -12331,6 +13060,16 @@
                     Slog.w(TAG, "Cannot hide package: android");
                     return false;
                 }
+                // Cannot hide static shared libs as they are considered
+                // a part of the using app (emulating static linking). Also
+                // static libs are installed always on internal storage.
+                PackageParser.Package pkg = mPackages.get(packageName);
+                if (pkg != null && pkg.staticSharedLibName != null) {
+                    Slog.w(TAG, "Cannot hide package: " + packageName
+                            + " providing static shared library: "
+                            + pkg.staticSharedLibName);
+                    return false;
+                }
                 // Only allow protected packages to hide themselves.
                 if (hidden && !UserHandle.isSameApp(uid, pkgSetting.appId)
                         && mProtectedPackages.isPackageStateProtected(userId, packageName)) {
@@ -12591,6 +13330,17 @@
             return false;
         }
 
+        // Cannot suspend static shared libs as they are considered
+        // a part of the using app (emulating static linking). Also
+        // static libs are installed always on internal storage.
+        PackageParser.Package pkg = mPackages.get(packageName);
+        if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+            Slog.w(TAG, "Cannot suspend package: " + packageName
+                    + " providing static shared library: "
+                    + pkg.staticSharedLibName);
+            return false;
+        }
+
         return true;
     }
 
@@ -13635,7 +14385,7 @@
                             origin.resolvedPath, isForwardLocked(), packageAbiOverride);
 
                     try {
-                        mInstaller.freeCache(null, sizeBytes + lowThreshold);
+                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0);
                         pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
                                 installFlags, packageAbiOverride);
                     } catch (InstallerException e) {
@@ -15024,6 +15774,7 @@
         res.removedInfo = new PackageRemovedInfo();
         res.removedInfo.uid = oldPackage.applicationInfo.uid;
         res.removedInfo.removedPackage = oldPackage.packageName;
+        res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null;
         res.removedInfo.isUpdate = true;
         res.removedInfo.origUsers = installedUsers;
         final PackageSetting ps = mSettings.getPackageLPr(pkgName);
@@ -15686,6 +16437,19 @@
             return;
         }
 
+        if (pkg.applicationInfo.isStaticSharedLibrary()) {
+            // Static shared libraries have synthetic package names
+            renameStaticSharedLibraryPackage(pkg);
+
+            // No static shared libs on external storage
+            if (onExternal) {
+                Slog.i(TAG, "Static shared libs can only be installed on internal storage.");
+                res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+                        "Packages declaring static-shared libs cannot be updated");
+                return;
+            }
+        }
+
         // If we are installing a clustered package add results for the children
         if (pkg.childPackages != null) {
             synchronized (mPackages) {
@@ -15810,11 +16574,23 @@
             if (ps != null) {
                 if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
 
+                // Static shared libs have same package with different versions where
+                // we internally use a synthetic package name to allow multiple versions
+                // of the same package, therefore we need to compare signatures against
+                // the package setting for the latest library version.
+                PackageSetting signatureCheckPs = ps;
+                if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                    SharedLibraryEntry libraryEntry = getLatestSharedLibraVersionLPr(pkg);
+                    if (libraryEntry != null) {
+                        signatureCheckPs = mSettings.getPackageLPr(libraryEntry.apk);
+                    }
+                }
+
                 // Quick sanity check that we're signed correctly if updating;
                 // we'll check this again later when scanning, but we want to
                 // bail early here before tripping over redefined permissions.
-                if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
-                    if (!checkUpgradeKeySetLP(ps, pkg)) {
+                if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
+                    if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
                         res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
                                 + pkg.packageName + " upgrade keys do not match the "
                                 + "previously installed version");
@@ -15822,7 +16598,7 @@
                     }
                 } else {
                     try {
-                        verifySignaturesLP(ps, pkg);
+                        verifySignaturesLP(signatureCheckPs, pkg);
                     } catch (PackageManagerException e) {
                         res.setError(e.error, e.getMessage());
                         return;
@@ -15939,14 +16715,6 @@
                 return;
             }
 
-            // Shared libraries for the package need to be updated.
-            synchronized (mPackages) {
-                try {
-                    updateSharedLibrariesLPr(pkg, null);
-                } catch (PackageManagerException e) {
-                    Slog.e(TAG, "updateSharedLibrariesLPw failed: " + e.getMessage());
-                }
-            }
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
             // Do not run PackageDexOptimizer through the local performDexOpt
             // method because `pkg` may not be in `mPackages` yet.
@@ -15974,6 +16742,18 @@
         try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
                 "installPackageLI")) {
             if (replace) {
+                if (pkg.applicationInfo.isStaticSharedLibrary()) {
+                    // Static libs have a synthetic package name containing the version
+                    // and cannot be updated as an update would get a new package name,
+                    // unless this is the exact same version code which is useful for
+                    // development.
+                    PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
+                    if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
+                        res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
+                                + "static-shared libs cannot be updated");
+                        return;
+                    }
+                }
                 replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
                         installerPackageName, res, args.installReason);
             } else {
@@ -16219,22 +16999,37 @@
     }
 
     @Override
-    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int userId,
-            int flags) {
-        deletePackage(packageName, new LegacyPackageDeleteObserver(observer).getBinder(), userId,
-                flags);
+    public void deletePackageAsUser(String packageName, int versionCode,
+            IPackageDeleteObserver observer, int userId, int flags) {
+        deletePackageVersioned(new VersionedPackage(packageName, versionCode),
+                new LegacyPackageDeleteObserver(observer).getBinder(), userId, flags);
     }
 
     @Override
-    public void deletePackage(final String packageName,
+    public void deletePackageVersioned(VersionedPackage versionedPackage,
             final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
-        Preconditions.checkNotNull(packageName);
+        Preconditions.checkNotNull(versionedPackage);
         Preconditions.checkNotNull(observer);
+        Preconditions.checkArgumentInRange(versionedPackage.getVersionCode(),
+                PackageManager.VERSION_CODE_HIGHEST,
+                Integer.MAX_VALUE, "versionCode must be >= -1");
+
+        final String packageName = versionedPackage.getPackageName();
+        // TODO: We will change version code to long, so in the new API it is long
+        final int versionCode = (int) versionedPackage.getVersionCode();
+        final String internalPackageName;
+        synchronized (mPackages) {
+            // Normalize package name to handle renamed packages and static libs
+            internalPackageName = resolveInternalPackageNameLPr(versionedPackage.getPackageName(),
+                    // TODO: We will change version code to long, so in the new API it is long
+                    (int) versionedPackage.getVersionCode());
+        }
+
         final int uid = Binder.getCallingUid();
-        if (!isOrphaned(packageName)
-                && !isCallerAllowedToSilentlyUninstall(uid, packageName)) {
+        if (!isOrphaned(internalPackageName)
+                && !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
             try {
                 final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
                 intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
@@ -16261,7 +17056,7 @@
             return;
         }
 
-        if (!deleteAllUsers && getBlockUninstallForUser(packageName, userId)) {
+        if (!deleteAllUsers && getBlockUninstallForUser(internalPackageName, userId)) {
             try {
                 observer.onPackageDeleted(packageName,
                         PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
@@ -16271,8 +17066,10 @@
         }
 
         if (DEBUG_REMOVE) {
-            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId
-                    + " deleteAllUsers: " + deleteAllUsers );
+            Slog.d(TAG, "deletePackageAsUser: pkg=" + internalPackageName + " user=" + userId
+                    + " deleteAllUsers: " + deleteAllUsers + " version="
+                    + (versionCode == PackageManager.VERSION_CODE_HIGHEST
+                    ? "VERSION_CODE_HIGHEST" : versionCode));
         }
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
@@ -16280,18 +17077,22 @@
                 mHandler.removeCallbacks(this);
                 int returnCode;
                 if (!deleteAllUsers) {
-                    returnCode = deletePackageX(packageName, userId, deleteFlags);
+                    returnCode = deletePackageX(internalPackageName, versionCode,
+                            userId, deleteFlags);
                 } else {
-                    int[] blockUninstallUserIds = getBlockUninstallForUsers(packageName, users);
+                    int[] blockUninstallUserIds = getBlockUninstallForUsers(
+                            internalPackageName, users);
                     // If nobody is blocking uninstall, proceed with delete for all users
                     if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
-                        returnCode = deletePackageX(packageName, userId, deleteFlags);
+                        returnCode = deletePackageX(internalPackageName, versionCode,
+                                userId, deleteFlags);
                     } else {
                         // Otherwise uninstall individually for users with blockUninstalls=false
                         final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS;
                         for (int userId : users) {
                             if (!ArrayUtils.contains(blockUninstallUserIds, userId)) {
-                                returnCode = deletePackageX(packageName, userId, userFlags);
+                                returnCode = deletePackageX(internalPackageName, versionCode,
+                                        userId, userFlags);
                                 if (returnCode != PackageManager.DELETE_SUCCEEDED) {
                                     Slog.w(TAG, "Package delete failed for user " + userId
                                             + ", returnCode " + returnCode);
@@ -16312,6 +17113,80 @@
         });
     }
 
+    private String resolveExternalPackageNameLPr(PackageParser.Package pkg) {
+        if (pkg.staticSharedLibName != null) {
+            return pkg.manifestPackageName;
+        }
+        return pkg.packageName;
+    }
+
+    private String resolveInternalPackageNameLPr(String packageName, int versionCode) {
+        // Handle renamed packages
+        String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
+        packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
+
+        // Is this a static library?
+        SparseArray<SharedLibraryEntry> versionedLib =
+                mStaticLibsByDeclaringPackage.get(packageName);
+        if (versionedLib == null || versionedLib.size() <= 0) {
+            return packageName;
+        }
+
+        // Figure out which lib versions the caller can see
+        SparseIntArray versionsCallerCanSee = null;
+        final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
+        if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
+                && callingAppId != Process.ROOT_UID) {
+            versionsCallerCanSee = new SparseIntArray();
+            String libName = versionedLib.valueAt(0).info.getName();
+            String[] uidPackages = getPackagesForUid(Binder.getCallingUid());
+            if (uidPackages != null) {
+                for (String uidPackage : uidPackages) {
+                    PackageSetting ps = mSettings.getPackageLPr(uidPackage);
+                    final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
+                    if (libIdx >= 0) {
+                        final int libVersion = ps.usesStaticLibrariesVersions[libIdx];
+                        versionsCallerCanSee.append(libVersion, libVersion);
+                    }
+                }
+            }
+        }
+
+        // Caller can see nothing - done
+        if (versionsCallerCanSee != null && versionsCallerCanSee.size() <= 0) {
+            return packageName;
+        }
+
+        // Find the version the caller can see and the app version code
+        SharedLibraryEntry highestVersion = null;
+        final int versionCount = versionedLib.size();
+        for (int i = 0; i < versionCount; i++) {
+            SharedLibraryEntry libEntry = versionedLib.valueAt(i);
+            if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
+                    libEntry.info.getVersion()) < 0) {
+                continue;
+            }
+            // TODO: We will change version code to long, so in the new API it is long
+            final int libVersionCode = (int) libEntry.info.getDeclaringPackage().getVersionCode();
+            if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
+                if (libVersionCode == versionCode) {
+                    return libEntry.apk;
+                }
+            } else if (highestVersion == null) {
+                highestVersion = libEntry;
+            } else if (libVersionCode  > highestVersion.info
+                    .getDeclaringPackage().getVersionCode()) {
+                highestVersion = libEntry;
+            }
+        }
+
+        if (highestVersion != null) {
+            return highestVersion.apk;
+        }
+
+        return packageName;
+    }
+
     private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
               || callingUid == Process.SYSTEM_UID) {
@@ -16410,7 +17285,7 @@
      *  persisting settings for later use
      *  sending a broadcast if necessary
      */
-    private int deletePackageX(String packageName, int userId, int deleteFlags) {
+    private int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) {
         final PackageRemovedInfo info = new PackageRemovedInfo();
         final boolean res;
 
@@ -16433,6 +17308,32 @@
                 Slog.w(TAG, "Not removing non-existent package " + packageName);
                 return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
             }
+
+            if (versionCode != PackageManager.VERSION_CODE_HIGHEST
+                    && uninstalledPs.versionCode != versionCode) {
+                Slog.w(TAG, "Not removing package " + packageName + " with versionCode "
+                        + uninstalledPs.versionCode + " != " + versionCode);
+                return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
+            }
+
+            // Static shared libs can be declared by any package, so let us not
+            // allow removing a package if it provides a lib others depend on.
+            PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg != null && pkg.staticSharedLibName != null) {
+                SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(pkg.staticSharedLibName,
+                        pkg.staticSharedLibVersion);
+                if (libEntry != null) {
+                    List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
+                            libEntry.info, 0, userId);
+                    if (!ArrayUtils.isEmpty(libClientPackages)) {
+                        Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+                                + " hosting lib " + libEntry.info.getName() + " version "
+                                + libEntry.info.getVersion()  + " used by " + libClientPackages);
+                        return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;
+                    }
+                }
+            }
+
             allUsers = sUserManager.getUserIds();
             info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
         }
@@ -16491,6 +17392,7 @@
         boolean isUpdate;
         boolean dataRemoved;
         boolean removedForAllUsers;
+        boolean isStaticSharedLib;
         // Clean up resources deleted packages.
         InstallArgs args = null;
         ArrayMap<String, PackageRemovedInfo> removedChildPackages;
@@ -16542,6 +17444,12 @@
         }
 
         private void sendPackageRemovedBroadcastInternal(boolean killApp) {
+            // Don't send static shared library removal broadcasts as these
+            // libs are visible only the the apps that depend on them an one
+            // cannot remove the library if it has a dependency.
+            if (isStaticSharedLib) {
+                return;
+            }
             Bundle extras = new Bundle(2);
             extras.putInt(Intent.EXTRA_UID, removedAppId >= 0  ? removedAppId : uid);
             extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
@@ -16555,7 +17463,8 @@
                         extras, 0, null, null, removedUsers);
                 if (dataRemoved && !isRemovedPackageSystemUpdate) {
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
-                            removedPackage, extras, 0, null, null, removedUsers);
+                            removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
+                            null, null, removedUsers);
                 }
             }
             if (removedAppId >= 0) {
@@ -16584,6 +17493,8 @@
             deletedPs = mSettings.mPackages.get(packageName);
             if (outInfo != null) {
                 outInfo.removedPackage = packageName;
+                outInfo.isStaticSharedLib = deletedPkg != null
+                        && deletedPkg.staticSharedLibName != null;
                 outInfo.removedUsers = deletedPs != null
                         ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
                         : null;
@@ -16611,15 +17522,18 @@
             schedulePackageCleaning(packageName, UserHandle.USER_ALL, true);
         }
 
+        int removedAppId = -1;
+
         // writer
         synchronized (mPackages) {
             if (deletedPs != null) {
                 if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
                     clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL);
                     clearDefaultBrowserIfNeeded(packageName);
+                    mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
+                    removedAppId = mSettings.removePackageLPw(packageName);
                     if (outInfo != null) {
-                        mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
-                        outInfo.removedAppId = mSettings.removePackageLPw(packageName);
+                        outInfo.removedAppId = removedAppId;
                     }
                     updatePermissionsLPw(deletedPs.name, null, 0);
                     if (deletedPs.sharedUser != null) {
@@ -16669,10 +17583,10 @@
                 mSettings.writeLPr();
             }
         }
-        if (outInfo != null) {
+        if (removedAppId != -1) {
             // A user ID was deleted here. Go through all users and remove it
             // from KeyStore.
-            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
+            removeKeystoreDataIfNeeded(UserHandle.USER_ALL, removedAppId);
         }
     }
 
@@ -16788,6 +17702,7 @@
                     + e.getMessage());
             return false;
         }
+
         try {
             // update shared libraries for the newly re-installed system package
             updateSharedLibrariesLPr(newPkg, null);
@@ -16906,6 +17821,15 @@
                 Log.i(TAG, "Package doesn't exist in set block uninstall " + packageName);
                 return false;
             }
+            // Cannot block uninstall of static shared libs as they are
+            // considered a part of the using app (emulating static linking).
+            // Also static libs are installed always on internal storage.
+            PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg != null && pkg.staticSharedLibName != null) {
+                Slog.w(TAG, "Cannot block uninstall of package: " + packageName
+                        + " providing static shared library: " + pkg.staticSharedLibName);
+                return false;
+            }
             if (!ps.getInstalled(userId)) {
                 // Can't block uninstall for an app that is not installed or enabled.
                 Log.i(TAG, "Package not installed in set block uninstall " + packageName);
@@ -16967,7 +17891,6 @@
         if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
 
         PackageSetting ps;
-
         synchronized (mPackages) {
             ps = mSettings.mPackages.get(packageName);
             if (ps == null) {
@@ -17160,6 +18083,7 @@
 
         if (outInfo != null) {
             outInfo.removedPackage = ps.name;
+            outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null;
             outInfo.removedAppId = ps.appId;
             outInfo.removedUsers = userIds;
         }
@@ -19180,6 +20104,7 @@
                     pw.println("Error: check-permission missing package argument");
                     return;
                 }
+
                 String pkg = args[opti];
                 opti++;
                 int user = UserHandle.getUserId(Binder.getCallingUid());
@@ -19192,6 +20117,10 @@
                         return;
                     }
                 }
+
+                // Normalize package name to handle renamed packages and static libs
+                pkg = resolveInternalPackageNameLPr(pkg, PackageManager.VERSION_CODE_HIGHEST);
+
                 pw.println(checkPermission(perm, pkg, user));
                 return;
             } else if ("l".equals(cmd) || "libraries".equals(cmd)) {
@@ -19344,41 +20273,41 @@
                 boolean printedHeader = false;
                 final Iterator<String> it = mSharedLibraries.keySet().iterator();
                 while (it.hasNext()) {
-                    String name = it.next();
-                    SharedLibraryEntry ent = mSharedLibraries.get(name);
-                    if (!checkin) {
-                        if (!printedHeader) {
-                            if (dumpState.onTitlePrinted())
-                                pw.println();
-                            pw.println("Libraries:");
-                            printedHeader = true;
-                        }
-                        pw.print("  ");
-                    } else {
-                        pw.print("lib,");
+                    String libName = it.next();
+                    SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+                    if (versionedLib == null) {
+                        continue;
                     }
-                    pw.print(name);
-                    if (!checkin) {
-                        pw.print(" -> ");
-                    }
-                    if (ent.path != null) {
+                    final int versionCount = versionedLib.size();
+                    for (int i = 0; i < versionCount; i++) {
+                        SharedLibraryEntry libEntry = versionedLib.valueAt(i);
                         if (!checkin) {
-                            pw.print("(jar) ");
-                            pw.print(ent.path);
+                            if (!printedHeader) {
+                                if (dumpState.onTitlePrinted())
+                                    pw.println();
+                                pw.println("Libraries:");
+                                printedHeader = true;
+                            }
+                            pw.print("  ");
                         } else {
-                            pw.print(",jar,");
-                            pw.print(ent.path);
+                            pw.print("lib,");
                         }
-                    } else {
+                        pw.print(libEntry.info.getName());
+                        if (libEntry.info.isStatic()) {
+                            pw.print(" version=" + libEntry.info.getVersion());
+                        }
                         if (!checkin) {
-                            pw.print("(apk) ");
-                            pw.print(ent.apk);
-                        } else {
-                            pw.print(",apk,");
-                            pw.print(ent.apk);
+                            pw.print(" -> ");
                         }
+                        if (libEntry.path != null) {
+                            pw.print(" (jar) ");
+                            pw.print(libEntry.path);
+                        } else {
+                            pw.print(" (apk) ");
+                            pw.print(libEntry.apk);
+                        }
+                        pw.println();
                     }
-                    pw.println();
                 }
             }
 
@@ -19509,7 +20438,8 @@
                             count = 0;
                             for (PackageSetting ps : allPackageSettings) {
                                 final long status = ps.getDomainVerificationStatusForUser(userId);
-                                if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+                                if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED
+                                        && !DEBUG_DOMAIN_VERIFICATION) {
                                     continue;
                                 }
                                 pw.println(prefix + "Package: " + ps.name);
@@ -20491,14 +21421,29 @@
         }
     }
 
+    private List<String> collectAbsoluteCodePaths() {
+        synchronized (mPackages) {
+            List<String> codePaths = new ArrayList<>();
+            final int packageCount = mSettings.mPackages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final PackageSetting ps = mSettings.mPackages.valueAt(i);
+                codePaths.add(ps.codePath.getAbsolutePath());
+            }
+            return codePaths;
+        }
+    }
+
     /**
      * Examine all apps present on given mounted volume, and destroy apps that
      * aren't expected, either due to uninstallation or reinstallation on
      * another volume.
      */
     private void reconcileApps(String volumeUuid) {
-        final File[] files = FileUtils
-                .listFilesOrEmpty(Environment.getDataAppDirectory(volumeUuid));
+        List<String> absoluteCodePaths = collectAbsoluteCodePaths();
+        List<File> filesToDelete = null;
+
+        final File[] files = FileUtils.listFilesOrEmpty(
+                Environment.getDataAppDirectory(volumeUuid));
         for (File file : files) {
             final boolean isPackage = (isApkFile(file) || file.isDirectory())
                     && !PackageInstallerService.isStageName(file.getName());
@@ -20507,15 +21452,33 @@
                 continue;
             }
 
-            try {
-                final PackageLite pkg = PackageParser.parsePackageLite(file,
-                        PackageParser.PARSE_MUST_BE_APK);
-                assertPackageKnown(volumeUuid, pkg.packageName);
+            String absolutePath = file.getAbsolutePath();
 
-            } catch (PackageParserException | PackageManagerException e) {
-                logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
+            boolean pathValid = false;
+            final int absoluteCodePathCount = absoluteCodePaths.size();
+            for (int i = 0; i < absoluteCodePathCount; i++) {
+                String absoluteCodePath = absoluteCodePaths.get(i);
+                if (absolutePath.startsWith(absoluteCodePath)) {
+                    pathValid = true;
+                    break;
+                }
+            }
+
+            if (!pathValid) {
+                if (filesToDelete == null) {
+                    filesToDelete = new ArrayList<>();
+                }
+                filesToDelete.add(file);
+            }
+        }
+
+        if (filesToDelete != null) {
+            final int fileToDeleteCount = filesToDelete.size();
+            for (int i = 0; i < fileToDeleteCount; i++) {
+                File fileToDelete = filesToDelete.get(i);
+                logCriticalInfo(Log.WARN, "Destroying orphaned" + fileToDelete);
                 synchronized (mInstallLock) {
-                    removeCodePathLI(file);
+                    removeCodePathLI(fileToDelete);
                 }
             }
         }
@@ -20970,6 +21933,14 @@
                         "Cannot move system application");
             }
 
+            final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
+            final boolean allow3rdPartyOnInternal = mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+            if (isInternalStorage && !allow3rdPartyOnInternal) {
+                throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
+                        "3rd party apps are not allowed on internal storage");
+            }
+
             if (pkg.applicationInfo.isExternalAsec()) {
                 currentAsec = true;
                 currentVolumeUuid = StorageManager.UUID_PRIMARY_PHYSICAL;
@@ -21285,7 +22256,8 @@
                 }
                 mHandler.post(new Runnable() {
                     public void run() {
-                        deletePackageX(packageName, userHandle, 0);
+                        deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
+                                userHandle, 0);
                     } //end run
                 });
             }
@@ -21495,7 +22467,8 @@
             // after this method returns.
             mHandler.post(new Runnable() {
                 public void run() {
-                    deletePackageX(packageName, 0, PackageManager.DELETE_ALL_USERS);
+                    deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
+                            0, PackageManager.DELETE_ALL_USERS);
                 }
             });
         }
@@ -21852,6 +22825,15 @@
                     responseObj, origIntent, resolvedType, launchIntent, callingPackage, userId);
         }
 
+        @Override
+        public void grantEphemeralAccess(int userId, Intent intent,
+                int targetAppId, int ephemeralAppId) {
+            synchronized (mPackages) {
+                mEphemeralApplicationRegistry.grantEphemeralAccessLPw(userId, intent,
+                        targetAppId, ephemeralAppId);
+            }
+        }
+
         public String getSetupWizardPackageName() {
             return mSetupWizardPackage;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 2751742..aa421b1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -40,6 +40,7 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.ResolveInfo;
+import android.content.pm.VersionedPackage;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
@@ -663,7 +664,8 @@
                     pw.print(info.applicationInfo.sourceDir);
                     pw.print("=");
                 }
-                pw.print(info.packageName);
+                pw.print(info.packageName); pw.print( " versionCode:"
+                        + info.applicationInfo.versionCode);
                 if (listInstaller) {
                     pw.print("  installer=");
                     pw.print(mInterface.getInstallerPackageName(info.packageName));
@@ -770,6 +772,7 @@
         final PrintWriter pw = getOutPrintWriter();
         int flags = 0;
         int userId = UserHandle.USER_ALL;
+        int versionCode = PackageManager.VERSION_CODE_HIGHEST;
 
         String opt;
         while ((opt = getNextOption()) != null) {
@@ -780,6 +783,9 @@
                 case "--user":
                     userId = UserHandle.parseUserArg(getNextArgRequired());
                     break;
+                case "--versionCode":
+                    versionCode = Integer.parseInt(getNextArgRequired());
+                    break;
                 default:
                     pw.println("Error: Unknown option: " + opt);
                     return 1;
@@ -819,7 +825,8 @@
         }
 
         final LocalIntentReceiver receiver = new LocalIntentReceiver();
-        mInterface.getPackageInstaller().uninstall(packageName, null /*callerPackageName*/, flags,
+        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
+                versionCode), null /*callerPackageName*/, flags,
                 receiver.getIntentSender(), userId);
 
         final Intent result = receiver.getResult();
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 80a398a..5f348ab 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -46,10 +46,12 @@
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
             int pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
-            List<String> childPackageNames, int sharedUserId) {
+            List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries,
+            int[] usesStaticLibrariesVersions) {
         super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
                 primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
-                pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames);
+                pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames,
+                usesStaticLibraries, usesStaticLibrariesVersions);
         this.sharedUserId = sharedUserId;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index b332fa5..b63edfd 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -32,6 +32,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
 
@@ -68,6 +69,9 @@
     File resourcePath;
     String resourcePathString;
 
+    String[] usesStaticLibraries;
+    int[] usesStaticLibrariesVersions;
+
     /**
      * The path under which native libraries have been unpacked. This path is
      * always derived at runtime, and is only stored here for cleanup when a
@@ -139,13 +143,16 @@
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
             int pVersionCode, int pkgFlags, int pkgPrivateFlags,
-            String parentPackageName, List<String> childPackageNames) {
+            String parentPackageName, List<String> childPackageNames,
+            String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
         super(pkgFlags, pkgPrivateFlags);
         this.name = name;
         this.realName = realName;
         this.parentPackageName = parentPackageName;
         this.childPackageNames = (childPackageNames != null)
                 ? new ArrayList<>(childPackageNames) : null;
+        this.usesStaticLibraries = usesStaticLibraries;
+        this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
         init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString,
                 secondaryCpuAbiString, cpuAbiOverrideString, pVersionCode);
     }
@@ -250,6 +257,12 @@
         versionCode = orig.versionCode;
         volumeUuid = orig.volumeUuid;
         categoryHint = orig.categoryHint;
+        usesStaticLibraries = orig.usesStaticLibraries != null
+                ? Arrays.copyOf(orig.usesStaticLibraries,
+                        orig.usesStaticLibraries.length) : null;
+        usesStaticLibrariesVersions = orig.usesStaticLibrariesVersions != null
+                ? Arrays.copyOf(orig.usesStaticLibrariesVersions,
+                       orig.usesStaticLibrariesVersions.length) : null;
     }
 
     private PackageUserState modifyUserState(int userId) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8761a6d..281e445 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -183,6 +183,7 @@
     private static final String TAG_RUNTIME_PERMISSIONS = "runtime-permissions";
     private static final String TAG_PERMISSIONS = "perms";
     private static final String TAG_CHILD_PACKAGE = "child-package";
+    private static final String TAG_USES_STATIC_LIB = "uses-static-lib";
 
     private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
             "persistent-preferred-activities";
@@ -201,6 +202,7 @@
     private static final String ATTR_CODE = "code";
     private static final String ATTR_GRANTED = "granted";
     private static final String ATTR_FLAGS = "flags";
+    private static final String ATTR_VERSION = "version";
 
     private static final String ATTR_CE_DATA_INODE = "ceDataInode";
     private static final String ATTR_INSTALLED = "inst";
@@ -561,7 +563,8 @@
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.cpuAbiOverrideString,
                 p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
-                p.parentPackageName, p.childPackageNames);
+                p.parentPackageName, p.childPackageNames, p.usesStaticLibraries,
+                p.usesStaticLibrariesVersions);
         mDisabledSysPackages.remove(name);
         return ret;
     }
@@ -578,7 +581,8 @@
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
             pkgFlags, int pkgPrivateFlags, String parentPackageName,
-            List<String> childPackageNames) {
+            List<String> childPackageNames, String[] usesStaticLibraries,
+            int[] usesStaticLibraryNames) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.appId == uid) {
@@ -591,7 +595,7 @@
         p = new PackageSetting(name, realName, codePath, resourcePath,
                 legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
                 cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName,
-                childPackageNames, 0 /*userId*/);
+                childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames);
         p.appId = uid;
         if (addUserIdLPw(uid, p, name)) {
             mPackages.put(name, p);
@@ -678,7 +682,8 @@
             File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
             String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags,
             UserHandle installUser, boolean allowInstall, String parentPkgName,
-            List<String> childPkgNames, UserManagerService userManager) {
+            List<String> childPkgNames, UserManagerService userManager,
+            String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
         final PackageSetting pkgSetting;
         if (originalPkg != null) {
             if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
@@ -699,13 +704,16 @@
             // overwrite the signatures in the original package setting.
             pkgSetting.signatures = new PackageSignatures();
             pkgSetting.versionCode = versionCode;
+            pkgSetting.usesStaticLibraries = usesStaticLibraries;
+            pkgSetting.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
             // Update new package state.
             pkgSetting.setTimeStamp(codePath.lastModified());
         } else {
             pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
                     legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
                     null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
-                    parentPkgName, childPkgNames, 0 /*sharedUserId*/);
+                    parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries,
+                    usesStaticLibrariesVersions);
             pkgSetting.setTimeStamp(codePath.lastModified());
             pkgSetting.sharedUser = sharedUser;
             // If this is not a system app, it starts out stopped.
@@ -782,7 +790,8 @@
             @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
             @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
             int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
-            @NonNull UserManagerService userManager) throws PackageManagerException {
+            @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries,
+            @Nullable int[] usesStaticLibrariesVersions) throws PackageManagerException {
         final String pkgName = pkgSetting.name;
         if (pkgSetting.sharedUser != sharedUser) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -844,6 +853,14 @@
         if (childPkgNames != null) {
             pkgSetting.childPackageNames = new ArrayList<>(childPkgNames);
         }
+        if (usesStaticLibraries != null) {
+            pkgSetting.usesStaticLibraries = Arrays.copyOf(usesStaticLibraries,
+                    usesStaticLibraries.length);
+        }
+        if (usesStaticLibrariesVersions != null) {
+            pkgSetting.usesStaticLibrariesVersions = Arrays.copyOf(usesStaticLibrariesVersions,
+                    usesStaticLibrariesVersions.length);
+        }
     }
 
     /**
@@ -949,6 +966,16 @@
         if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
             p.sharedUser.signatures.assignSignatures(pkg.mSignatures);
         }
+        // Update static shared library dependencies if needed
+        if (pkg.usesStaticLibraries != null && pkg.usesStaticLibrariesVersions != null
+                && pkg.usesStaticLibraries.size() == pkg.usesStaticLibrariesVersions.length) {
+            String[] usesStaticLibraries = new String[pkg.usesStaticLibraries.size()];
+            pkg.usesStaticLibraries.toArray(usesStaticLibraries);
+            p.usesStaticLibrariesVersions = pkg.usesStaticLibrariesVersions;
+        } else {
+            pkg.usesStaticLibraries = null;
+            p.usesStaticLibrariesVersions = null;
+        }
         addPackageSettingLPw(p, p.sharedUser);
     }
 
@@ -2163,6 +2190,53 @@
         }
     }
 
+    void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs)
+            throws IOException, XmlPullParserException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String libName = parser.getAttributeValue(null, ATTR_NAME);
+            String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION);
+
+            int libVersion = -1;
+            try {
+                libVersion = Integer.parseInt(libVersionStr);
+            } catch (NumberFormatException e) {
+                // ignore
+            }
+
+            if (libName != null && libVersion >= 0) {
+                outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class,
+                        outPs.usesStaticLibraries, libName);
+                outPs.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+                        outPs.usesStaticLibrariesVersions, libVersion);
+            }
+
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+
+    void writeUsesStaticLibLPw(XmlSerializer serializer, String[] usesStaticLibraries,
+            int[] usesStaticLibraryVersions) throws IOException {
+        if (ArrayUtils.isEmpty(usesStaticLibraries) || ArrayUtils.isEmpty(usesStaticLibraryVersions)
+                || usesStaticLibraries.length != usesStaticLibraryVersions.length) {
+            return;
+        }
+        final int libCount = usesStaticLibraries.length;
+        for (int i = 0; i < libCount; i++) {
+            final String libName = usesStaticLibraries[i];
+            final int libVersion = usesStaticLibraryVersions[i];
+            serializer.startTag(null, TAG_USES_STATIC_LIB);
+            serializer.attribute(null, ATTR_NAME, libName);
+            serializer.attribute(null, ATTR_VERSION, Integer.toString(libVersion));
+            serializer.endTag(null, TAG_USES_STATIC_LIB);
+        }
+    }
+
     // Note: assumed "stopped" field is already cleared in all packages.
     // Legacy reader, used to read in the old file format after an upgrade. Not used after that.
     void readStoppedLPw() {
@@ -2622,6 +2696,8 @@
 
         writeChildPackagesLPw(serializer, pkg.childPackageNames);
 
+        writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+
         // If this is a shared user, the permissions will be written there.
         if (pkg.sharedUser == null) {
             writePermissionsLPr(serializer, pkg.getPermissionsState()
@@ -2692,6 +2768,8 @@
 
         writeChildPackagesLPw(serializer, pkg.childPackageNames);
 
+        writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
+
         pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
 
         writePermissionsLPr(serializer, pkg.getPermissionsState()
@@ -3465,7 +3543,7 @@
         PackageSetting ps = new PackageSetting(name, realName, codePathFile,
                 new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
                 secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
-                parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/);
+                parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null);
         String timeStampStr = parser.getAttributeValue(null, "ft");
         if (timeStampStr != null) {
             try {
@@ -3520,6 +3598,8 @@
                     ps.childPackageNames = new ArrayList<>();
                 }
                 ps.childPackageNames.add(childPackageName);
+            } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) {
+                readUsesStaticLibLPw(parser, ps);
             } else {
                 PackageManagerService.reportSettingsProblem(Log.WARN,
                         "Unknown element under <updated-package>: " + parser.getName());
@@ -3705,7 +3785,8 @@
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
                         new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
                         secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
-                        pkgPrivateFlags, parentPackageName, null /*childPackageNames*/);
+                        pkgPrivateFlags, parentPackageName, null /*childPackageNames*/,
+                        null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
                             + userId + " pkg=" + packageSetting);
@@ -3724,7 +3805,8 @@
                             codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
                             primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
                             versionCode, pkgFlags, pkgPrivateFlags, parentPackageName,
-                            null /*childPackageNames*/, sharedUserId);
+                            null /*childPackageNames*/, sharedUserId,
+                            null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/);
                     packageSetting.setTimeStamp(timeStamp);
                     packageSetting.firstInstallTime = firstInstallTime;
                     packageSetting.lastUpdateTime = lastUpdateTime;
@@ -4294,6 +4376,7 @@
         ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET, "RESIZEABLE_ACTIVITIES_EXPLICITLY_SET",
         ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION, "RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION",
         ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
+        ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
     };
 
     void dumpVersionLPr(IndentingPrintWriter pw) {
@@ -4486,23 +4569,39 @@
             }
             pw.println("]");
             if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) {
-                pw.print(prefix); pw.println("  libraries:");
-                for (int i=0; i<ps.pkg.libraryNames.size(); i++) {
-                    pw.print(prefix); pw.print("    "); pw.println(ps.pkg.libraryNames.get(i));
+                pw.print(prefix); pw.println("  dynamic libraries:");
+                for (int i = 0; i<ps.pkg.libraryNames.size(); i++) {
+                    pw.print(prefix); pw.print("    ");
+                            pw.println(ps.pkg.libraryNames.get(i));
                 }
             }
+            if (ps.pkg.staticSharedLibName != null) {
+                pw.print(prefix); pw.println("  static library:");
+                pw.print(prefix); pw.print("    ");
+                pw.print("name:"); pw.print(ps.pkg.staticSharedLibName);
+                pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion);
+            }
             if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesLibraries:");
                 for (int i=0; i<ps.pkg.usesLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    "); pw.println(ps.pkg.usesLibraries.get(i));
                 }
             }
+            if (ps.pkg.usesStaticLibraries != null
+                    && ps.pkg.usesStaticLibraries.size() > 0) {
+                pw.print(prefix); pw.println("  usesStaticLibraries:");
+                for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) {
+                    pw.print(prefix); pw.print("    ");
+                    pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:");
+                            pw.println(ps.pkg.usesStaticLibrariesVersions[i]);
+                }
+            }
             if (ps.pkg.usesOptionalLibraries != null
                     && ps.pkg.usesOptionalLibraries.size() > 0) {
                 pw.print(prefix); pw.println("  usesOptionalLibraries:");
                 for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) {
                     pw.print(prefix); pw.print("    ");
-                        pw.println(ps.pkg.usesOptionalLibraries.get(i));
+                    pw.println(ps.pkg.usesOptionalLibraries.get(i));
                 }
             }
             if (ps.pkg.usesLibraryFiles != null
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index c8ddf0a..6e96726 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.pm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -24,6 +25,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.ShortcutInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
@@ -50,18 +52,31 @@
     private static class PinItemRequestInner extends IPinItemRequest.Stub {
         protected final ShortcutRequestPinProcessor mProcessor;
         private final IntentSender mResultIntent;
+        private final int mLauncherUid;
 
         @GuardedBy("this")
         private boolean mAccepted;
 
         private PinItemRequestInner(ShortcutRequestPinProcessor processor,
-                IntentSender resultIntent) {
+                IntentSender resultIntent, int launcherUid) {
             mProcessor = processor;
             mResultIntent = resultIntent;
+            mLauncherUid = launcherUid;
+        }
+
+        /**
+         * Returns true if the caller is same as the default launcher app when this request
+         * object was created.
+         */
+        private boolean isCallerValid() {
+            return mProcessor.isCallerUid(mLauncherUid);
         }
 
         @Override
         public boolean isValid() {
+            if (!isCallerValid()) {
+                return false;
+            }
             // TODO When an app calls requestPinShortcut(), all pending requests should be
             // invalidated.
             synchronized (this) {
@@ -76,6 +91,9 @@
         public boolean accept(Bundle options) {
             // Make sure the options are unparcellable by the FW. (e.g. not containing unknown
             // classes.)
+            if (!isCallerValid()) {
+                throw new SecurityException("Calling uid mismatch");
+            }
             Intent extras = null;
             if (options != null) {
                 try {
@@ -126,8 +144,8 @@
         private PinShortcutRequestInner(ShortcutRequestPinProcessor processor,
                 ShortcutInfo shortcutOriginal, ShortcutInfo shortcutForLauncher,
                 IntentSender resultIntent,
-                String launcherPackage, int launcherUserId, boolean preExisting) {
-            super(processor, resultIntent);
+                String launcherPackage, int launcherUserId, int launcherUid, boolean preExisting) {
+            super(processor, resultIntent, launcherUid);
             this.shortcutOriginal = shortcutOriginal;
             this.shortcutForLauncher = shortcutForLauncher;
             this.launcherPackage = launcherPackage;
@@ -157,6 +175,7 @@
     /**
      * Handle {@link android.content.pm.ShortcutManager#requestPinShortcut)} and
      * {@link android.appwidget.AppWidgetManager#requestPinAppWidget}.
+     * In this flow the PinItemRequest is delivered directly to the default launcher app.
      * One of {@param inShortcut} and {@param inAppWidget} is always non-null and the other is
      * always null.
      */
@@ -186,21 +205,44 @@
         if (inShortcut != null) {
             request = requestPinShortcutLocked(inShortcut, resultIntent, confirmActivity);
         } else {
-            request = new PinItemRequest(inAppWidget, new PinItemRequestInner(this, resultIntent));
-        }
-
-        if (request == null) {
-            sendResultIntent(resultIntent, null);
-            return true;
+            int launcherUid = mService.injectGetPackageUid(
+                    confirmActivity.first.getPackageName(), launcherUserId);
+            request = new PinItemRequest(inAppWidget,
+                    new PinItemRequestInner(this, resultIntent, launcherUid));
         }
         return startRequestConfirmActivity(confirmActivity.first, launcherUserId, request);
     }
 
     /**
+     * Handle {@link android.content.pm.ShortcutManager#createShortcutResultIntent(ShortcutInfo)}.
+     * In this flow the PinItemRequest is delivered to the caller app. Its the app's responsibility
+     * to send it to the Launcher app (via {@link android.app.Activity#setResult(int, Intent)}).
+     */
+    public Intent createShortcutResultIntent(@NonNull ShortcutInfo inShortcut, int userId) {
+        // Find the default launcher activity
+        final int launcherUserId = mService.getParentOrSelfUserId(userId);
+        final ComponentName defaultLauncher = mService.getDefaultLauncher(launcherUserId);
+        if (defaultLauncher == null) {
+            Log.e(TAG, "Default launcher not found.");
+            return null;
+        }
+
+        // Make sure the launcher user is unlocked. (it's always the parent profile, so should
+        // really be unlocked here though.)
+        mService.throwIfUserLockedL(launcherUserId);
+
+        // Next, validate the incoming shortcut, etc.
+        final PinItemRequest request = requestPinShortcutLocked(inShortcut, null,
+                Pair.create(defaultLauncher, launcherUserId));
+        return new Intent().putExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST, request);
+    }
+
+    /**
      * Handle {@link android.content.pm.ShortcutManager#requestPinShortcut)}.
      */
+    @NonNull
     private PinItemRequest requestPinShortcutLocked(ShortcutInfo inShortcut,
-            IntentSender resultIntent, Pair<ComponentName, Integer> confirmActivity) {
+            IntentSender resultIntentOriginal, Pair<ComponentName, Integer> confirmActivity) {
         final ShortcutPackage ps = mService.getPackageShortcutsForPublisherLocked(
                 inShortcut.getPackage(), inShortcut.getUserId());
 
@@ -218,23 +260,30 @@
         final String launcherPackage = confirmActivity.first.getPackageName();
         final int launcherUserId = confirmActivity.second;
 
+        IntentSender resultIntentToSend = resultIntentOriginal;
+
         if (existsAlready) {
             validateExistingShortcut(existing);
 
-            // See if it's already pinned.
-            if (mService.getLauncherShortcutsLocked(
-                    launcherPackage, existing.getUserId(), launcherUserId).hasPinned(existing)) {
-                Log.i(TAG, "Launcher's already pinning shortcut " + existing.getId()
-                        + " for package " + existing.getPackage());
-                return null;
+            final boolean isAlreadyPinned = mService.getLauncherShortcutsLocked(
+                    launcherPackage, existing.getUserId(), launcherUserId).hasPinned(existing);
+            if (isAlreadyPinned) {
+                // When the shortcut is already pinned by this launcher, the request will always
+                // succeed, so just send the result at this point.
+                sendResultIntent(resultIntentOriginal, null);
+
+                // So, do not send the intent again.
+                resultIntentToSend = null;
             }
 
             // Pass a clone, not the original.
             // Note this will remove the intent and icons.
             shortcutForLauncher = existing.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
 
-            // FLAG_PINNED is still set, if it's pinned by other launchers.
-            shortcutForLauncher.clearFlags(ShortcutInfo.FLAG_PINNED);
+            if (!isAlreadyPinned) {
+                // FLAG_PINNED may still be set, if it's pinned by other launchers.
+                shortcutForLauncher.clearFlags(ShortcutInfo.FLAG_PINNED);
+            }
         } else {
             // If the shortcut has no default activity, try to set the main activity.
             // But in the request-pin case, it's optional, so it's okay even if the caller
@@ -263,8 +312,10 @@
 
         // Create a request object.
         final PinShortcutRequestInner inner =
-                new PinShortcutRequestInner(this, inShortcut, shortcutForLauncher, resultIntent,
-                        launcherPackage, launcherUserId, existsAlready);
+                new PinShortcutRequestInner(this, inShortcut, shortcutForLauncher,
+                        resultIntentToSend, launcherPackage, launcherUserId,
+                        mService.injectGetPackageUid(launcherPackage, launcherUserId),
+                        existsAlready);
 
         return new PinItemRequest(shortcutForLauncher, inner);
     }
@@ -327,6 +378,10 @@
         mService.injectSendIntentSender(intent, extras);
     }
 
+    public boolean isCallerUid(int uid) {
+        return uid == mService.injectBinderCallingUid();
+    }
+
     /**
      * The last step of the "request pin shortcut" flow.  Called when the launcher accepted a
      * request.
@@ -347,6 +402,16 @@
                 return false;
             }
 
+            final ShortcutLauncher launcher = mService.getLauncherShortcutsLocked(
+                    launcherPackage, appUserId, launcherUserId);
+            launcher.attemptToRestoreIfNeededAndSave();
+            if (launcher.hasPinned(original)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Shortcut " + original + " already pinned.");
+                }
+                return true;
+            }
+
             final ShortcutPackage ps = mService.getPackageShortcutsForPublisherLocked(
                     appPackageName, appUserId);
             final ShortcutInfo current = ps.findShortcutById(shortcutId);
@@ -384,9 +449,6 @@
                 Slog.d(TAG, "Pinning " + shortcutId);
             }
 
-            final ShortcutLauncher launcher = mService.getLauncherShortcutsLocked(
-                    launcherPackage, appUserId, launcherUserId);
-            launcher.attemptToRestoreIfNeededAndSave();
             launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId);
 
             if (current == null) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a890526..56d679e 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1529,10 +1529,11 @@
         if (UserHandle.getUserId(callingUid) != userId) {
             throw new SecurityException("Invalid user-ID");
         }
-        if (injectGetPackageUid(packageName, userId) == injectBinderCallingUid()) {
-            return; // Caller is valid.
+        if (injectGetPackageUid(packageName, userId) != callingUid) {
+            throw new SecurityException("Calling package name mismatch");
         }
-        throw new SecurityException("Calling package name mismatch");
+        Preconditions.checkState(!isEphemeralApp(packageName, userId),
+                "Ephemeral apps can't use ShortcutManager");
     }
 
     // Overridden in unit tests to execute r synchronously.
@@ -1854,6 +1855,25 @@
         return requestPinItem(packageName, userId, shortcut, null, resultIntent);
     }
 
+    @Override
+    public Intent createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId)
+            throws RemoteException {
+        Preconditions.checkNotNull(shortcut);
+        Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
+        verifyCaller(packageName, userId);
+
+        final Intent ret;
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            // Send request to the launcher, if supported.
+            ret = mShortcutRequestPinProcessor.createShortcutResultIntent(shortcut, userId);
+        }
+
+        verifyStates();
+        return ret;
+    }
+
     /**
      * Handles {@link #requestPinShortcut} and {@link ShortcutServiceInternal#requestPinAppWidget}.
      * After validating the caller, it passes the request to {@link #mShortcutRequestPinProcessor}.
@@ -3054,6 +3074,10 @@
         return (ai != null) && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
     }
 
+    private static boolean isEphemeralApp(@Nullable ApplicationInfo ai) {
+        return (ai != null) && ai.isEphemeralApp();
+    }
+
     private static boolean isInstalled(@Nullable PackageInfo pi) {
         return (pi != null) && isInstalled(pi.applicationInfo);
     }
@@ -3078,6 +3102,10 @@
         return getApplicationInfo(packageName, userId) != null;
     }
 
+    boolean isEphemeralApp(String packageName, int userId) {
+        return isEphemeralApp(getApplicationInfo(packageName, userId));
+    }
+
     @Nullable
     XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
         return activityInfo.loadXmlMetaData(mContext.getPackageManager(), key);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9fc70d6..1eb8b94 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -67,6 +67,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManager.EnforcingUser;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
@@ -118,6 +119,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -162,7 +164,11 @@
     private static final String TAG_USER = "user";
     private static final String TAG_RESTRICTIONS = "restrictions";
     private static final String TAG_DEVICE_POLICY_RESTRICTIONS = "device_policy_restrictions";
+    private static final String TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS =
+            "device_policy_global_restrictions";
+    /** Legacy name for device owner id tag. */
     private static final String TAG_GLOBAL_RESTRICTION_OWNER_ID = "globalRestrictionOwnerUserId";
+    private static final String TAG_DEVICE_OWNER_USER_ID = "deviceOwnerUserId";
     private static final String TAG_ENTRY = "entry";
     private static final String TAG_VALUE = "value";
     private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
@@ -202,7 +208,7 @@
     @VisibleForTesting
     static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;
 
-    private static final int USER_VERSION = 6;
+    private static final int USER_VERSION = 7;
 
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
@@ -267,7 +273,7 @@
 
     /**
      * User restrictions set via UserManager.  This doesn't include restrictions set by
-     * device owner / profile owners.
+     * device owner / profile owners. Only non-empty restriction bundles are stored.
      *
      * DO NOT Change existing {@link Bundle} in it.  When changing a restriction for a user,
      * a new {@link Bundle} should always be created and set.  This is because a {@link Bundle}
@@ -305,20 +311,21 @@
 
     /**
      * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
-     * that should be applied to all users, including guests.
+     * that should be applied to all users, including guests. Only non-empty restriction bundles are
+     * stored.
      */
     @GuardedBy("mRestrictionsLock")
-    private Bundle mDevicePolicyGlobalUserRestrictions;
+    private final SparseArray<Bundle> mDevicePolicyGlobalUserRestrictions = new SparseArray<>();
 
     /**
      * Id of the user that set global restrictions.
      */
     @GuardedBy("mRestrictionsLock")
-    private int mGlobalRestrictionOwnerUserId = UserHandle.USER_NULL;
+    private int mDeviceOwnerUserId = UserHandle.USER_NULL;
 
     /**
      * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
-     * for each user.
+     * for each user. Only non-empty restriction bundles are stored.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mDevicePolicyLocalUserRestrictions = new SparseArray<>();
@@ -1176,39 +1183,36 @@
     }
 
     /**
-     * See {@link UserManagerInternal#setDevicePolicyUserRestrictions(int, Bundle, Bundle)}
+     * See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
      */
-    void setDevicePolicyUserRestrictionsInner(int userId, @NonNull Bundle local,
-            @Nullable Bundle global) {
-        Preconditions.checkNotNull(local);
-        boolean globalChanged = false;
-        boolean localChanged;
+    private void setDevicePolicyUserRestrictionsInner(int userId, @Nullable Bundle restrictions,
+            boolean isDeviceOwner, int cameraRestrictionScope) {
+        final Bundle global = new Bundle();
+        final Bundle local = new Bundle();
+
+        // Sort restrictions into local and global ensuring they don't overlap.
+        UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, isDeviceOwner,
+                cameraRestrictionScope, global, local);
+
+        boolean globalChanged, localChanged;
         synchronized (mRestrictionsLock) {
-            if (global != null) {
-                // Update global.
-                globalChanged = !UserRestrictionsUtils.areEqual(
-                        mDevicePolicyGlobalUserRestrictions, global);
-                if (globalChanged) {
-                    mDevicePolicyGlobalUserRestrictions = global;
-                }
+            // Update global and local restrictions if they were changed.
+            globalChanged = updateRestrictionsIfNeededLR(
+                    userId, global, mDevicePolicyGlobalUserRestrictions);
+            localChanged = updateRestrictionsIfNeededLR(
+                    userId, local, mDevicePolicyLocalUserRestrictions);
+
+            if (isDeviceOwner) {
                 // Remember the global restriction owner userId to be able to make a distinction
                 // in getUserRestrictionSource on who set local policies.
-                mGlobalRestrictionOwnerUserId = userId;
+                mDeviceOwnerUserId = userId;
             } else {
-                if (mGlobalRestrictionOwnerUserId == userId) {
+                if (mDeviceOwnerUserId == userId) {
                     // When profile owner sets restrictions it passes null global bundle and we
                     // reset global restriction owner userId.
                     // This means this user used to have DO, but now the DO is gone and the user
                     // instead has PO.
-                    mGlobalRestrictionOwnerUserId = UserHandle.USER_NULL;
-                }
-            }
-            {
-                // Update local.
-                final Bundle prev = mDevicePolicyLocalUserRestrictions.get(userId);
-                localChanged = !UserRestrictionsUtils.areEqual(prev, local);
-                if (localChanged) {
-                    mDevicePolicyLocalUserRestrictions.put(userId, local);
+                    mDeviceOwnerUserId = UserHandle.USER_NULL;
                 }
             }
         }
@@ -1220,12 +1224,9 @@
         }
         // Don't call them within the mRestrictionsLock.
         synchronized (mPackagesLock) {
-            if (localChanged) {
+            if (localChanged || globalChanged) {
                 writeUserLP(getUserDataNoChecks(userId));
             }
-            if (globalChanged) {
-                writeUserListLP();
-            }
         }
 
         synchronized (mRestrictionsLock) {
@@ -1237,11 +1238,30 @@
         }
     }
 
+    /**
+     * Updates restriction bundle for a given user in a given restriction array. If new bundle is
+     * empty, record is removed from the array.
+     * @return whether restrictions bundle is different from the old one.
+     */
+    private boolean updateRestrictionsIfNeededLR(int userId, @Nullable Bundle restrictions,
+            SparseArray<Bundle> restrictionsArray) {
+        final boolean changed =
+                !UserRestrictionsUtils.areEqual(restrictionsArray.get(userId), restrictions);
+        if (changed) {
+            if (!UserRestrictionsUtils.isEmpty(restrictions)) {
+                restrictionsArray.put(userId, restrictions);
+            } else {
+                restrictionsArray.delete(userId);
+            }
+        }
+        return changed;
+    }
+
     @GuardedBy("mRestrictionsLock")
     private Bundle computeEffectiveUserRestrictionsLR(int userId) {
         final Bundle baseRestrictions =
                 UserRestrictionsUtils.nonNull(mBaseUserRestrictions.get(userId));
-        final Bundle global = mDevicePolicyGlobalUserRestrictions;
+        final Bundle global = UserRestrictionsUtils.mergeAll(mDevicePolicyGlobalUserRestrictions);
         final Bundle local = mDevicePolicyLocalUserRestrictions.get(userId);
 
         if (UserRestrictionsUtils.isEmpty(global) && UserRestrictionsUtils.isEmpty(local)) {
@@ -1299,39 +1319,58 @@
      */
     @Override
     public int getUserRestrictionSource(String restrictionKey, int userId) {
-        checkManageUsersPermission("getUserRestrictionSource");
+        List<EnforcingUser> enforcingUsers = getUserRestrictionSources(restrictionKey,  userId);
+        // Get "bitwise or" of restriction sources for all enforcing users.
         int result = UserManager.RESTRICTION_NOT_SET;
+        for (int i = enforcingUsers.size() - 1; i >= 0; i--) {
+            result |= enforcingUsers.get(i).getUserRestrictionSource();
+        }
+        return result;
+    }
+
+    @Override
+    public List<EnforcingUser> getUserRestrictionSources(
+            String restrictionKey, @UserIdInt int userId) {
+        checkManageUsersPermission("getUserRestrictionSource");
 
         // Shortcut for the most common case
         if (!hasUserRestriction(restrictionKey, userId)) {
-            return result;
+            return Collections.emptyList();
         }
 
+        final List<EnforcingUser> result = new ArrayList<>();
+
+        // Check if it is base restriction.
         if (hasBaseUserRestriction(restrictionKey, userId)) {
-            result |= UserManager.RESTRICTION_SOURCE_SYSTEM;
+            result.add(new EnforcingUser(
+                    UserHandle.USER_NULL, UserManager.RESTRICTION_SOURCE_SYSTEM));
         }
 
-        synchronized(mRestrictionsLock) {
-            Bundle localRestrictions = mDevicePolicyLocalUserRestrictions.get(userId);
-            if (!UserRestrictionsUtils.isEmpty(localRestrictions)
-                    && localRestrictions.getBoolean(restrictionKey)) {
-                // Local restrictions may have been set by device owner the userId of which is
-                // stored in mGlobalRestrictionOwnerUserId.
-                if (mGlobalRestrictionOwnerUserId == userId) {
-                    result |= UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
-                } else {
-                    result |= UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
+        synchronized (mRestrictionsLock) {
+            // Check if it is set by profile owner.
+            Bundle profileOwnerRestrictions = mDevicePolicyLocalUserRestrictions.get(userId);
+            if (UserRestrictionsUtils.contains(profileOwnerRestrictions, restrictionKey)) {
+                result.add(getEnforcingUserLocked(userId));
+            }
+
+            // Iterate over all users who enforce global restrictions.
+            for (int i = mDevicePolicyGlobalUserRestrictions.size() - 1; i >= 0; i--) {
+                Bundle globalRestrictions = mDevicePolicyGlobalUserRestrictions.valueAt(i);
+                int profileUserId = mDevicePolicyGlobalUserRestrictions.keyAt(i);
+                if (UserRestrictionsUtils.contains(globalRestrictions, restrictionKey)) {
+                    result.add(getEnforcingUserLocked(profileUserId));
                 }
             }
-            if (!UserRestrictionsUtils.isEmpty(mDevicePolicyGlobalUserRestrictions)
-                    && mDevicePolicyGlobalUserRestrictions.getBoolean(restrictionKey)) {
-                result |= UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
-            }
         }
-
         return result;
     }
 
+    private EnforcingUser getEnforcingUserLocked(@UserIdInt int userId) {
+        int source = mDeviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER
+                : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
+        return new EnforcingUser(userId, source);
+    }
+
     /**
      * @return UserRestrictions that are in effect currently.  This always returns a new
      * {@link Bundle}.
@@ -1374,28 +1413,26 @@
      * Optionally updating user restrictions, calculate the effective user restrictions and also
      * propagate to other services and system settings.
      *
-     * @param newRestrictions User restrictions to set.
+     * @param newBaseRestrictions User restrictions to set.
      *      If null, will not update user restrictions and only does the propagation.
      * @param userId target user ID.
      */
     @GuardedBy("mRestrictionsLock")
     private void updateUserRestrictionsInternalLR(
-            @Nullable Bundle newRestrictions, int userId) {
-
+            @Nullable Bundle newBaseRestrictions, int userId) {
         final Bundle prevAppliedRestrictions = UserRestrictionsUtils.nonNull(
                 mAppliedUserRestrictions.get(userId));
 
         // Update base restrictions.
-        if (newRestrictions != null) {
-            // If newRestrictions == the current one, it's probably a bug.
+        if (newBaseRestrictions != null) {
+            // If newBaseRestrictions == the current one, it's probably a bug.
             final Bundle prevBaseRestrictions = mBaseUserRestrictions.get(userId);
 
-            Preconditions.checkState(prevBaseRestrictions != newRestrictions);
+            Preconditions.checkState(prevBaseRestrictions != newBaseRestrictions);
             Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId)
-                    != newRestrictions);
+                    != newBaseRestrictions);
 
-            if (!UserRestrictionsUtils.areEqual(prevBaseRestrictions, newRestrictions)) {
-                mBaseUserRestrictions.put(userId, newRestrictions);
+            if (updateRestrictionsIfNeededLR(userId, newBaseRestrictions, mBaseUserRestrictions)) {
                 scheduleWriteUser(getUserDataNoChecks(userId));
             }
         }
@@ -1530,7 +1567,7 @@
         }
         synchronized(mUsersLock) {
             UserInfo userInfo = getUserInfoLU(userId);
-            if (!userInfo.canHaveProfile()) {
+            if (userInfo == null || !userInfo.canHaveProfile()) {
                 return false;
             }
             int usersCountAfterRemoving = getAliveUsersExcludingGuestsCountLU()
@@ -1746,7 +1783,9 @@
                 }
             }
 
-            final Bundle newDevicePolicyGlobalUserRestrictions = new Bundle();
+            // Pre-O global user restriction were stored as a single bundle (as opposed to per-user
+            // currently), take care of it in case of upgrade.
+            Bundle oldDevicePolicyGlobalUserRestrictions = null;
 
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (type == XmlPullParser.START_TAG) {
@@ -1771,29 +1810,30 @@
                             if (type == XmlPullParser.START_TAG) {
                                 if (parser.getName().equals(TAG_RESTRICTIONS)) {
                                     synchronized (mGuestRestrictions) {
-                                        UserRestrictionsUtils
-                                                .readRestrictions(parser, mGuestRestrictions);
+                                        mGuestRestrictions.putAll(
+                                                UserRestrictionsUtils.readRestrictions(parser));
                                     }
                                 }
                                 break;
                             }
                         }
-                    } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
-                        UserRestrictionsUtils.readRestrictions(parser,
-                                newDevicePolicyGlobalUserRestrictions);
-                    } else if (name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
+                    } else if (name.equals(TAG_DEVICE_OWNER_USER_ID)
+                            // Legacy name, should only be encountered when upgrading from pre-O.
+                            || name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
                         String ownerUserId = parser.getAttributeValue(null, ATTR_ID);
                         if (ownerUserId != null) {
-                            mGlobalRestrictionOwnerUserId = Integer.parseInt(ownerUserId);
+                            mDeviceOwnerUserId = Integer.parseInt(ownerUserId);
                         }
+                    } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
+                        // Should only happen when upgrading from pre-O (version < 7).
+                        oldDevicePolicyGlobalUserRestrictions =
+                                UserRestrictionsUtils.readRestrictions(parser);
                     }
                 }
             }
-            synchronized (mRestrictionsLock) {
-                mDevicePolicyGlobalUserRestrictions = newDevicePolicyGlobalUserRestrictions;
-            }
+
             updateUserIds();
-            upgradeIfNecessaryLP();
+            upgradeIfNecessaryLP(oldDevicePolicyGlobalUserRestrictions);
         } catch (IOException | XmlPullParserException e) {
             fallbackToSingleUserLP();
         } finally {
@@ -1803,8 +1843,9 @@
 
     /**
      * Upgrade steps between versions, either for fixing bugs or changing the data format.
+     * @param oldGlobalUserRestrictions Pre-O global device policy restrictions.
      */
-    private void upgradeIfNecessaryLP() {
+    private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
         final int originalVersion = mUserVersion;
         int userVersion = mUserVersion;
         if (userVersion < 1) {
@@ -1855,6 +1896,23 @@
             userVersion = 6;
         }
 
+        if (userVersion < 7) {
+            // Previously only one user could enforce global restrictions, now it is per-user.
+            synchronized (mRestrictionsLock) {
+                if (!UserRestrictionsUtils.isEmpty(oldGlobalUserRestrictions)
+                        && mDeviceOwnerUserId != UserHandle.USER_NULL) {
+                    mDevicePolicyGlobalUserRestrictions.put(
+                            mDeviceOwnerUserId, oldGlobalUserRestrictions);
+                }
+                // ENSURE_VERIFY_APPS is now enforced globally even if put by profile owner, so move
+                // it from local to global bundle for all users who set it.
+                UserRestrictionsUtils.moveRestriction(UserManager.ENSURE_VERIFY_APPS,
+                        mDevicePolicyLocalUserRestrictions, mDevicePolicyGlobalUserRestrictions
+                );
+            }
+            userVersion = 7;
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);
@@ -1893,8 +1951,10 @@
             Log.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e);
         }
 
-        synchronized (mRestrictionsLock) {
-            mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+        if (!restrictions.isEmpty()) {
+            synchronized (mRestrictionsLock) {
+                mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+            }
         }
 
         updateUserIds();
@@ -2004,6 +2064,9 @@
             UserRestrictionsUtils.writeRestrictions(serializer,
                     mDevicePolicyLocalUserRestrictions.get(userInfo.id),
                     TAG_DEVICE_POLICY_RESTRICTIONS);
+            UserRestrictionsUtils.writeRestrictions(serializer,
+                    mDevicePolicyGlobalUserRestrictions.get(userInfo.id),
+                    TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
         }
 
         if (userData.account != null) {
@@ -2057,13 +2120,9 @@
                         .writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
-            synchronized (mRestrictionsLock) {
-                UserRestrictionsUtils.writeRestrictions(serializer,
-                        mDevicePolicyGlobalUserRestrictions, TAG_DEVICE_POLICY_RESTRICTIONS);
-            }
-            serializer.startTag(null, TAG_GLOBAL_RESTRICTION_OWNER_ID);
-            serializer.attribute(null, ATTR_ID, Integer.toString(mGlobalRestrictionOwnerUserId));
-            serializer.endTag(null, TAG_GLOBAL_RESTRICTION_OWNER_ID);
+            serializer.startTag(null, TAG_DEVICE_OWNER_USER_ID);
+            serializer.attribute(null, ATTR_ID, Integer.toString(mDeviceOwnerUserId));
+            serializer.endTag(null, TAG_DEVICE_OWNER_USER_ID);
             int[] userIdsToWrite;
             synchronized (mUsersLock) {
                 userIdsToWrite = new int[mUsers.size()];
@@ -2125,8 +2184,9 @@
         String seedAccountName = null;
         String seedAccountType = null;
         PersistableBundle seedAccountOptions = null;
-        Bundle baseRestrictions = new Bundle();
-        Bundle localRestrictions = new Bundle();
+        Bundle baseRestrictions = null;
+        Bundle localRestrictions = null;
+        Bundle globalRestrictions = null;
 
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(is, StandardCharsets.UTF_8.name());
@@ -2187,9 +2247,11 @@
                         name = parser.getText();
                     }
                 } else if (TAG_RESTRICTIONS.equals(tag)) {
-                    UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
+                    baseRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
-                    UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
+                    localRestrictions = UserRestrictionsUtils.readRestrictions(parser);
+                } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) {
+                    globalRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_ACCOUNT.equals(tag)) {
                     type = parser.next();
                     if (type == XmlPullParser.TEXT) {
@@ -2224,8 +2286,15 @@
         userData.seedAccountOptions = seedAccountOptions;
 
         synchronized (mRestrictionsLock) {
-            mBaseUserRestrictions.put(id, baseRestrictions);
-            mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+            if (baseRestrictions != null) {
+                mBaseUserRestrictions.put(id, baseRestrictions);
+            }
+            if (localRestrictions != null) {
+                mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+            }
+            if (globalRestrictions != null) {
+                mDevicePolicyGlobalUserRestrictions.put(id, globalRestrictions);
+            }
         }
         return userData;
     }
@@ -2731,6 +2800,10 @@
             mAppliedUserRestrictions.remove(userHandle);
             mCachedEffectiveUserRestrictions.remove(userHandle);
             mDevicePolicyLocalUserRestrictions.remove(userHandle);
+            if (mDevicePolicyGlobalUserRestrictions.get(userHandle) != null) {
+                mDevicePolicyGlobalUserRestrictions.remove(userHandle);
+                applyUserRestrictionsForAllUsersLR();
+            }
         }
         // Update the user list
         synchronized (mPackagesLock) {
@@ -3420,6 +3493,9 @@
                     synchronized (mRestrictionsLock) {
                         UserRestrictionsUtils.dumpRestrictions(
                                 pw, "      ", mBaseUserRestrictions.get(userInfo.id));
+                        pw.println("    Device policy global restrictions:");
+                        UserRestrictionsUtils.dumpRestrictions(
+                                pw, "      ", mDevicePolicyGlobalUserRestrictions.get(userInfo.id));
                         pw.println("    Device policy local restrictions:");
                         UserRestrictionsUtils.dumpRestrictions(
                                 pw, "      ", mDevicePolicyLocalUserRestrictions.get(userInfo.id));
@@ -3448,13 +3524,7 @@
                 }
             }
             pw.println();
-            pw.println("  Device policy global restrictions:");
-            synchronized (mRestrictionsLock) {
-                UserRestrictionsUtils
-                        .dumpRestrictions(pw, "    ", mDevicePolicyGlobalUserRestrictions);
-            }
-            pw.println();
-            pw.println("  Global restrictions owner id:" + mGlobalRestrictionOwnerUserId);
+            pw.println("  Device owner id:" + mDeviceOwnerUserId);
             pw.println();
             pw.println("  Guest restrictions:");
             synchronized (mGuestRestrictions) {
@@ -3508,10 +3578,10 @@
 
     private class LocalService extends UserManagerInternal {
         @Override
-        public void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle localRestrictions,
-                @Nullable Bundle globalRestrictions) {
-            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, localRestrictions,
-                    globalRestrictions);
+        public void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
+                boolean isDeviceOwner, int cameraRestrictionScope) {
+            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, restrictions,
+                isDeviceOwner, cameraRestrictionScope);
         }
 
         @Override
@@ -3525,8 +3595,10 @@
         public void setBaseUserRestrictionsByDpmsForMigration(
                 int userId, Bundle baseRestrictions) {
             synchronized (mRestrictionsLock) {
-                mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions));
-                invalidateEffectiveUserRestrictionsLR(userId);
+                if (updateRestrictionsIfNeededLR(
+                        userId, new Bundle(baseRestrictions), mBaseUserRestrictions)) {
+                    invalidateEffectiveUserRestrictionsLR(userId);
+                }
             }
 
             final UserData userData = getUserDataNoChecks(userId);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f5b8669..d301463 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -30,11 +30,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -117,9 +119,10 @@
     );
 
     /**
-     * User restrictions that can not be set by profile owners.
+     * User restrictions that cannot be set by profile owners of secondary users. When set by DO
+     * they will be applied to all users.
      */
-    private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
+    private static final Set<String> PRIMARY_USER_ONLY_RESTRICTIONS = Sets.newArraySet(
             UserManager.DISALLOW_BLUETOOTH,
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_TETHERING,
@@ -163,6 +166,13 @@
             UserManager.DISALLOW_ADD_MANAGED_PROFILE
     );
 
+    /*
+     * Special user restrictions that are always applied to all users no matter who sets them.
+     */
+    private static final Set<String> PROFILE_GLOBAL_RESTRICTIONS = Sets.newArraySet(
+            UserManager.ENSURE_VERIFY_APPS
+    );
+
     /**
      * Throws {@link IllegalArgumentException} if the given restriction name is invalid.
      */
@@ -205,6 +215,12 @@
         }
     }
 
+    public static Bundle readRestrictions(XmlPullParser parser) {
+        final Bundle result = new Bundle();
+        readRestrictions(parser, result);
+        return result;
+    }
+
     /**
      * @return {@code in} itself when it's not null, or an empty bundle (which can writable).
      */
@@ -217,6 +233,14 @@
     }
 
     /**
+     * Returns {@code true} if given bundle is not null and contains {@code true} for a given
+     * restriction.
+     */
+    public static boolean contains(@Nullable Bundle in, String restriction) {
+        return in != null && in.getBoolean(restriction);
+    }
+
+    /**
      * Creates a copy of the {@code in} Bundle.  If {@code in} is null, it'll return an empty
      * bundle.
      *
@@ -241,6 +265,22 @@
     }
 
     /**
+     * Merges a sparse array of restrictions bundles into one.
+     */
+    @Nullable
+    public static Bundle mergeAll(SparseArray<Bundle> restrictions) {
+        if (restrictions.size() == 0) {
+            return null;
+        } else {
+            final Bundle result = new Bundle();
+            for (int i = 0; i < restrictions.size(); i++) {
+                merge(result, restrictions.valueAt(i));
+            }
+            return result;
+        }
+    }
+
+    /**
      * @return true if a restriction is settable by device owner.
      */
     public static boolean canDeviceOwnerChange(String restriction) {
@@ -254,7 +294,7 @@
     public static boolean canProfileOwnerChange(String restriction, int userId) {
         return !IMMUTABLE_BY_OWNERS.contains(restriction)
                 && !(userId != UserHandle.USER_SYSTEM
-                    && DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction));
+                    && PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction));
     }
 
     /**
@@ -269,8 +309,15 @@
      * Takes restrictions that can be set by device owner, and sort them into what should be applied
      * globally and what should be applied only on the current user.
      */
-    public static void sortToGlobalAndLocal(@Nullable Bundle in, @NonNull Bundle global,
-            @NonNull Bundle local) {
+    public static void sortToGlobalAndLocal(@Nullable Bundle in, boolean isDeviceOwner,
+            int cameraRestrictionScope,
+            @NonNull Bundle global, @NonNull Bundle local) {
+        // Camera restriction (as well as all others) goes to at most one bundle.
+        if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_GLOBALLY) {
+            global.putBoolean(UserManager.DISALLOW_CAMERA, true);
+        } else if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_LOCALLY) {
+            local.putBoolean(UserManager.DISALLOW_CAMERA, true);
+        }
         if (in == null || in.size() == 0) {
             return;
         }
@@ -278,7 +325,7 @@
             if (!in.getBoolean(key)) {
                 continue;
             }
-            if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)) {
+            if (isGlobal(isDeviceOwner, key)) {
                 global.putBoolean(key, true);
             } else {
                 local.putBoolean(key, true);
@@ -287,6 +334,15 @@
     }
 
     /**
+     * Whether given user restriction should be enforced globally.
+     */
+    private static boolean isGlobal(boolean isDeviceOwner, String key) {
+        return (isDeviceOwner &&
+                (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key)|| GLOBAL_RESTRICTIONS.contains(key)))
+                || PROFILE_GLOBAL_RESTRICTIONS.contains(key);
+    }
+
+    /**
      * @return true if two Bundles contain the same user restriction.
      * A null bundle and an empty bundle are considered to be equal.
      */
@@ -485,4 +541,29 @@
             pw.println(prefix + "null");
         }
     }
+
+    /**
+     * Moves a particular restriction from one array of bundles to another, e.g. for all users.
+     */
+    public static void moveRestriction(String restrictionKey, SparseArray<Bundle> srcRestrictions,
+            SparseArray<Bundle> destRestrictions) {
+        for (int i = 0; i < srcRestrictions.size(); i++) {
+            int key = srcRestrictions.keyAt(i);
+            Bundle from = srcRestrictions.valueAt(i);
+            if (contains(from, restrictionKey)) {
+                from.remove(restrictionKey);
+                Bundle to = destRestrictions.get(key);
+                if (to == null) {
+                    to = new Bundle();
+                    destRestrictions.append(key, to);
+                }
+                to.putBoolean(restrictionKey, true);
+                // Don't keep empty bundles.
+                if (from.isEmpty()) {
+                    srcRestrictions.removeAt(i);
+                    i--;
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
new file mode 100644
index 0000000..133881a
--- /dev/null
+++ b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.server.policy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.ContentObserver;
+import android.media.AudioAttributes;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+
+import android.widget.Toast;
+import com.android.internal.R;
+
+import java.util.List;
+
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+
+/**
+ * Class to help manage the accessibility shortcut
+ */
+public class AccessibilityShortcutController {
+    private static final String TAG = "AccessibilityShortcutController";
+
+    private final Context mContext;
+    private AlertDialog mAlertDialog;
+    private boolean mIsShortcutEnabled;
+    // Visible for testing
+    public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
+
+    public static String getTargetServiceComponentNameString(
+            Context context, int userId) {
+        final String currentShortcutServiceId = Settings.Secure.getStringForUser(
+                context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                userId);
+        if (currentShortcutServiceId != null) {
+            return currentShortcutServiceId;
+        }
+        return context.getString(R.string.config_defaultAccessibilityService);
+    }
+
+    public AccessibilityShortcutController(Context context, Handler handler) {
+        mContext = context;
+
+        // Keep track of state of shortcut
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
+                false,
+                new ContentObserver(handler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        onSettingsChanged();
+                    }
+                },
+                UserHandle.USER_ALL);
+        updateShortcutEnabled();
+    }
+
+    public boolean isAccessibilityShortcutAvailable() {
+        return mIsShortcutEnabled;
+    }
+
+    public void onSettingsChanged() {
+        updateShortcutEnabled();
+    }
+
+    /**
+     * Called when the accessibility shortcut is activated
+     */
+    public void performAccessibilityShortcut() {
+        Slog.d(TAG, "Accessibility shortcut activated");
+        final ContentResolver cr = mContext.getContentResolver();
+        final int userId = ActivityManager.getCurrentUser();
+        final int dialogAlreadyShown = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
+        final Ringtone tone =
+                RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
+        if (tone != null) {
+            tone.setAudioAttributes(new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+                .build());
+            tone.play();
+        }
+        if (dialogAlreadyShown == 0) {
+            // The first time, we show a warning rather than toggle the service to give the user a
+            // chance to turn off this feature before stuff gets enabled.
+            mAlertDialog = createShortcutWarningDialog(userId);
+            if (mAlertDialog == null) {
+                return;
+            }
+            Window w = mAlertDialog.getWindow();
+            WindowManager.LayoutParams attr = w.getAttributes();
+            attr.type = TYPE_KEYGUARD_DIALOG;
+            w.setAttributes(attr);
+            mAlertDialog.show();
+            Settings.Secure.putIntForUser(
+                    cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId);
+        } else {
+            if (mAlertDialog != null) {
+                mAlertDialog.dismiss();
+                mAlertDialog = null;
+            }
+
+            // Show a toast alerting the user to what's happening
+            final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+            if (serviceInfo == null) {
+                Slog.e(TAG, "Accessibility shortcut set to invalid service");
+                return;
+            }
+            String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
+                    ? R.string.accessibility_shortcut_disabling_service
+                    : R.string.accessibility_shortcut_enabling_service);
+            String toastMessage = String.format(toastMessageFormatString,
+                    serviceInfo.getResolveInfo()
+                            .loadLabel(mContext.getPackageManager()).toString());
+            mFrameworkObjectProvider.makeToastFromText(mContext, toastMessage, Toast.LENGTH_LONG)
+                    .show();
+
+            mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)
+                    .performAccessibilityShortcut();
+        }
+    }
+
+    private void updateShortcutEnabled() {
+        mIsShortcutEnabled = !TextUtils.isEmpty(getTargetServiceComponentNameString(
+                mContext, UserHandle.myUserId()));
+    }
+
+    private AlertDialog createShortcutWarningDialog(int userId) {
+        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+
+        if (serviceInfo == null) {
+            return null;
+        }
+
+        final String warningMessage = String.format(
+                mContext.getString(R.string.accessibility_shortcut_toogle_warning),
+                serviceInfo.getResolveInfo().loadLabel(mContext.getPackageManager()).toString());
+        final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(mContext)
+                .setTitle(R.string.accessibility_shortcut_warning_dialog_title)
+                .setMessage(warningMessage)
+                .setCancelable(false)
+                .setPositiveButton(R.string.leave_accessibility_shortcut_on, null)
+                .setNegativeButton(R.string.disable_accessibility_shortcut,
+                        (DialogInterface d, int which) -> {
+                            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "",
+                                    userId);
+                        })
+                .setOnCancelListener((DialogInterface d) -> {
+                    // If canceled, treat as if the dialog has never been shown
+                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
+                })
+                .create();
+        return alertDialog;
+    }
+
+    private AccessibilityServiceInfo getInfoForTargetService() {
+        final String currentShortcutServiceString = getTargetServiceComponentNameString(
+                mContext, UserHandle.myUserId());
+        if (currentShortcutServiceString == null) {
+            return null;
+        }
+        AccessibilityManager accessibilityManager =
+                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
+        return accessibilityManager.getInstalledServiceInfoWithComponentName(
+                        ComponentName.unflattenFromString(currentShortcutServiceString));
+    }
+
+    private boolean isServiceEnabled(AccessibilityServiceInfo serviceInfo) {
+        AccessibilityManager accessibilityManager =
+                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
+        return accessibilityManager.getEnabledAccessibilityServiceList(
+                AccessibilityServiceInfo.FEEDBACK_ALL_MASK).contains(serviceInfo);
+    }
+
+    // Class to allow mocking of static framework calls
+    public static class FrameworkObjectProvider {
+        public AccessibilityManager getAccessibilityManagerInstance(Context context) {
+            return AccessibilityManager.getInstance(context);
+        }
+
+        public AlertDialog.Builder getAlertDialogBuilder(Context context) {
+            return new AlertDialog.Builder(context);
+        }
+
+        public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) {
+            return Toast.makeText(context, charSequence, duration);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
deleted file mode 100644
index 6b203a9..0000000
--- a/services/core/java/com/android/server/policy/EnableAccessibilityController.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-package com.android.server.policy;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.speech.tts.TextToSpeech;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.IWindowManager;
-import android.view.MotionEvent;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-
-import com.android.internal.R;
-import com.android.server.LocalServices;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-public class EnableAccessibilityController {
-    private static final String TAG = "EnableAccessibilityController";
-
-    private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
-    private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
-
-    public static final int MESSAGE_SPEAK_WARNING = 1;
-    public static final int MESSAGE_SPEAK_ENABLE_CANCELED = 2;
-    public static final int MESSAGE_ENABLE_ACCESSIBILITY = 3;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message message) {
-            switch (message.what) {
-                case MESSAGE_SPEAK_WARNING: {
-                    String text = mContext.getString(R.string.continue_to_enable_accessibility);
-                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-                case MESSAGE_SPEAK_ENABLE_CANCELED: {
-                    String text = mContext.getString(R.string.enable_accessibility_canceled);
-                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-                case MESSAGE_ENABLE_ACCESSIBILITY: {
-                    enableAccessibility();
-                    mTone.play();
-                    mTts.speak(mContext.getString(R.string.accessibility_enabled),
-                            TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-            }
-        }
-    };
-
-    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
-            .Stub.asInterface(ServiceManager.getService("accessibility"));
-
-
-    private final Context mContext;
-    private final Runnable mOnAccessibilityEnabledCallback;
-    private final UserManager mUserManager;
-    private final TextToSpeech mTts;
-    private final Ringtone mTone;
-
-    private final float mTouchSlop;
-
-    private boolean mDestroyed;
-    private boolean mCanceled;
-
-    private float mFirstPointerDownX;
-    private float mFirstPointerDownY;
-    private float mSecondPointerDownX;
-    private float mSecondPointerDownY;
-
-    public EnableAccessibilityController(Context context, Runnable onAccessibilityEnabledCallback) {
-        mContext = context;
-        mOnAccessibilityEnabledCallback = onAccessibilityEnabledCallback;
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
-            @Override
-            public void onInit(int status) {
-                if (mDestroyed) {
-                    mTts.shutdown();
-                }
-            }
-        });
-        mTone = RingtoneManager.getRingtone(context, Settings.System.DEFAULT_NOTIFICATION_URI);
-        mTone.setStreamType(AudioManager.STREAM_MUSIC);
-        mTouchSlop = context.getResources().getDimensionPixelSize(
-                R.dimen.accessibility_touch_slop);
-    }
-
-    public static boolean canEnableAccessibilityViaGesture(Context context) {
-        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
-        // Accessibility is enabled and there is an enabled speaking
-        // accessibility service, then we have nothing to do.
-        if (accessibilityManager.isEnabled()
-                && !accessibilityManager.getEnabledAccessibilityServiceList(
-                        AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty()) {
-            return false;
-        }
-        // If the global gesture is enabled and there is a speaking service
-        // installed we are good to go, otherwise there is nothing to do.
-        return Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1
-                && !getInstalledSpeakingAccessibilityServices(context).isEmpty();
-    }
-
-    public static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
-            Context context) {
-        List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
-        services.addAll(AccessibilityManager.getInstance(context)
-                .getInstalledAccessibilityServiceList());
-        Iterator<AccessibilityServiceInfo> iterator = services.iterator();
-        while (iterator.hasNext()) {
-            AccessibilityServiceInfo service = iterator.next();
-            if ((service.feedbackType & AccessibilityServiceInfo.FEEDBACK_SPOKEN) == 0) {
-                iterator.remove();
-            }
-        }
-        return services;
-    }
-
-    public void onDestroy() {
-        mDestroyed = true;
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
-                && event.getPointerCount() == 2) {
-            mFirstPointerDownX = event.getX(0);
-            mFirstPointerDownY = event.getY(0);
-            mSecondPointerDownX = event.getX(1);
-            mSecondPointerDownY = event.getY(1);
-            mHandler.sendEmptyMessageDelayed(MESSAGE_SPEAK_WARNING,
-                    SPEAK_WARNING_DELAY_MILLIS);
-            mHandler.sendEmptyMessageDelayed(MESSAGE_ENABLE_ACCESSIBILITY,
-                   ENABLE_ACCESSIBILITY_DELAY_MILLIS);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean onTouchEvent(MotionEvent event) {
-        final int pointerCount = event.getPointerCount();
-        final int action = event.getActionMasked();
-        if (mCanceled) {
-            if (action == MotionEvent.ACTION_UP) {
-                mCanceled = false;
-            }
-            return true;
-        }
-        switch (action) {
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                if (pointerCount > 2) {
-                    cancel();
-                }
-            } break;
-            case MotionEvent.ACTION_MOVE: {
-                final float firstPointerMove = MathUtils.dist(event.getX(0),
-                        event.getY(0), mFirstPointerDownX, mFirstPointerDownY);
-                if (Math.abs(firstPointerMove) > mTouchSlop) {
-                    cancel();
-                }
-                final float secondPointerMove = MathUtils.dist(event.getX(1),
-                        event.getY(1), mSecondPointerDownX, mSecondPointerDownY);
-                if (Math.abs(secondPointerMove) > mTouchSlop) {
-                    cancel();
-                }
-            } break;
-            case MotionEvent.ACTION_POINTER_UP:
-            case MotionEvent.ACTION_CANCEL: {
-                cancel();
-            } break;
-        }
-        return true;
-    }
-
-    private void cancel() {
-        mCanceled = true;
-        if (mHandler.hasMessages(MESSAGE_SPEAK_WARNING)) {
-            mHandler.removeMessages(MESSAGE_SPEAK_WARNING);
-        } else if (mHandler.hasMessages(MESSAGE_ENABLE_ACCESSIBILITY)) {
-            mHandler.sendEmptyMessage(MESSAGE_SPEAK_ENABLE_CANCELED);
-        }
-        mHandler.removeMessages(MESSAGE_ENABLE_ACCESSIBILITY);
-    }
-
-    private void enableAccessibility() {
-        if (enableAccessibility(mContext)) {
-            mOnAccessibilityEnabledCallback.run();
-        }
-    }
-
-    public static boolean enableAccessibility(Context context) {
-        final IAccessibilityManager accessibilityManager = IAccessibilityManager
-                .Stub.asInterface(ServiceManager.getService("accessibility"));
-        final WindowManagerInternal windowManager = LocalServices.getService(
-                WindowManagerInternal.class);
-        final UserManager userManager = (UserManager) context.getSystemService(
-                Context.USER_SERVICE);
-        ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
-        if (componentName == null) {
-            return false;
-        }
-
-        boolean keyguardLocked = windowManager.isKeyguardLocked();
-        final boolean hasMoreThanOneUser = userManager.getUsers().size() > 1;
-        try {
-            if (!keyguardLocked || !hasMoreThanOneUser) {
-                final int userId = ActivityManager.getCurrentUser();
-                accessibilityManager.enableAccessibilityService(componentName, userId);
-            } else if (keyguardLocked) {
-                accessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
-                        componentName, true /* enableTouchExploration */);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "cannot enable accessibilty: " + e);
-        }
-
-        return true;
-    }
-
-    public static void disableAccessibility(Context context) {
-        final IAccessibilityManager accessibilityManager = IAccessibilityManager
-                .Stub.asInterface(ServiceManager.getService("accessibility"));
-        ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
-        if (componentName == null) {
-            return;
-        }
-
-        final int userId = ActivityManager.getCurrentUser();
-        try {
-            accessibilityManager.disableAccessibilityService(componentName, userId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "cannot disable accessibility " + e);
-        }
-    }
-
-    public static boolean isAccessibilityEnabled(Context context) {
-        final AccessibilityManager accessibilityManager =
-                context.getSystemService(AccessibilityManager.class);
-        List enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
-                AccessibilityServiceInfo.FEEDBACK_SPOKEN);
-        return enabledServices != null && !enabledServices.isEmpty();
-    }
-
-    @Nullable
-    public static ComponentName getInstalledSpeakingAccessibilityServiceComponent(
-            Context context) {
-        List<AccessibilityServiceInfo> services =
-                getInstalledSpeakingAccessibilityServices(context);
-        if (services.isEmpty()) {
-            return null;
-        }
-
-        ServiceInfo serviceInfo = services.get(0).getResolveInfo().serviceInfo;
-        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
-    }
-}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index d4adcc4..335a230 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -44,7 +44,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -59,12 +58,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.TypedValue;
-import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -1194,21 +1190,14 @@
 
     private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
         private final Context mContext;
-        private final int mWindowTouchSlop;
         private final AlertController mAlert;
         private final MyAdapter mAdapter;
 
-        private EnableAccessibilityController mEnableAccessibilityController;
-
-        private boolean mIntercepted;
-        private boolean mCancelOnUp;
-
         public GlobalActionsDialog(Context context, AlertParams params) {
             super(context, getDialogTheme(context));
             mContext = getContext();
             mAlert = AlertController.create(mContext, this, getWindow());
             mAdapter = (MyAdapter) params.mAdapter;
-            mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
             params.apply(mAlert);
         }
 
@@ -1221,76 +1210,10 @@
 
         @Override
         protected void onStart() {
-            // If global accessibility gesture can be performed, we will take care
-            // of dismissing the dialog on touch outside. This is because the dialog
-            // is dismissed on the first down while the global gesture is a long press
-            // with two fingers anywhere on the screen.
-            if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
-                mEnableAccessibilityController = new EnableAccessibilityController(mContext,
-                        new Runnable() {
-                    @Override
-                    public void run() {
-                        dismiss();
-                    }
-                });
-                super.setCanceledOnTouchOutside(false);
-            } else {
-                mEnableAccessibilityController = null;
-                super.setCanceledOnTouchOutside(true);
-            }
-
+            super.setCanceledOnTouchOutside(true);
             super.onStart();
         }
 
-        @Override
-        protected void onStop() {
-            if (mEnableAccessibilityController != null) {
-                mEnableAccessibilityController.onDestroy();
-            }
-            super.onStop();
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent event) {
-            if (mEnableAccessibilityController != null) {
-                final int action = event.getActionMasked();
-                if (action == MotionEvent.ACTION_DOWN) {
-                    View decor = getWindow().getDecorView();
-                    final int eventX = (int) event.getX();
-                    final int eventY = (int) event.getY();
-                    if (eventX < -mWindowTouchSlop
-                            || eventY < -mWindowTouchSlop
-                            || eventX >= decor.getWidth() + mWindowTouchSlop
-                            || eventY >= decor.getHeight() + mWindowTouchSlop) {
-                        mCancelOnUp = true;
-                    }
-                }
-                try {
-                    if (!mIntercepted) {
-                        mIntercepted = mEnableAccessibilityController.onInterceptTouchEvent(event);
-                        if (mIntercepted) {
-                            final long now = SystemClock.uptimeMillis();
-                            event = MotionEvent.obtain(now, now,
-                                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-                            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
-                            mCancelOnUp = true;
-                        }
-                    } else {
-                        return mEnableAccessibilityController.onTouchEvent(event);
-                    }
-                } finally {
-                    if (action == MotionEvent.ACTION_UP) {
-                        if (mCancelOnUp) {
-                            cancel();
-                        }
-                        mCancelOnUp = false;
-                        mIntercepted = false;
-                    }
-                }
-            }
-            return super.dispatchTouchEvent(event);
-        }
-
         public ListView getListView() {
             return mAlert.getListView();
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4b2b184..c25ad46 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -19,6 +19,8 @@
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.content.Context.DISPLAY_SERVICE;
+import static android.content.Context.WINDOW_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
@@ -140,6 +142,7 @@
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
@@ -149,8 +152,6 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.IAudioService;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
 import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
 import android.os.Build;
@@ -441,6 +442,9 @@
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
 
+    /** Controller that supports enabling an AccessibilityService by holding down the volume keys */
+    private AccessibilityShortcutController mAccessibilityShortcutController;
+
     boolean mSafeMode;
     WindowState mStatusBar = null;
     int mStatusBarHeight;
@@ -748,7 +752,10 @@
     private boolean mScreenshotChordVolumeDownKeyTriggered;
     private long mScreenshotChordVolumeDownKeyTime;
     private boolean mScreenshotChordVolumeDownKeyConsumed;
-    private boolean mScreenshotChordVolumeUpKeyTriggered;
+    private boolean mA11yShortcutChordVolumeUpKeyTriggered;
+    private long mA11yShortcutChordVolumeUpKeyTime;
+    private boolean mA11yShortcutChordVolumeUpKeyConsumed;
+
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
@@ -794,6 +801,7 @@
     private static final int MSG_BACK_LONG_PRESS = 18;
     private static final int MSG_DISPOSE_INPUT_CONSUMER = 19;
     private static final int MSG_BACK_DELAYED_PRESS = 20;
+    private static final int MSG_ACCESSIBILITY_SHORTCUT = 21;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -869,6 +877,9 @@
                     backMultiPressAction((Long) msg.obj, msg.arg1);
                     finishBackKeyPress();
                     break;
+                case MSG_ACCESSIBILITY_SHORTCUT:
+                    accessibilityShortcutActivated();
+                    break;
             }
         }
     }
@@ -1213,7 +1224,7 @@
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
         mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
-                || mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
+                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
         if (!mPowerKeyHandled) {
             if (interactive) {
                 // When interactive, we're already awake.
@@ -1406,9 +1417,7 @@
             break;
         case LONG_PRESS_POWER_GLOBAL_ACTIONS:
             mPowerKeyHandled = true;
-            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                performAuditoryFeedbackForAccessibilityIfNeed();
-            }
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
             showGlobalActionsInternal();
             break;
         case LONG_PRESS_POWER_SHUT_OFF:
@@ -1439,6 +1448,10 @@
         }
     }
 
+    private void accessibilityShortcutActivated() {
+        mAccessibilityShortcutController.performAccessibilityShortcut();
+    }
+
     private void disposeInputConsumer(InputConsumer inputConsumer) {
         if (inputConsumer != null) {
             inputConsumer.dismiss();
@@ -1484,7 +1497,7 @@
     private void interceptScreenshotChord() {
         if (mScreenshotChordEnabled
                 && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
-                && !mScreenshotChordVolumeUpKeyTriggered) {
+                && !mA11yShortcutChordVolumeUpKeyTriggered) {
             final long now = SystemClock.uptimeMillis();
             if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
                     && now <= mScreenshotChordPowerKeyTime
@@ -1497,6 +1510,22 @@
         }
     }
 
+    private void interceptAccessibilityShortcutChord() {
+        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable()
+                && mScreenshotChordVolumeDownKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered
+                && !mScreenshotChordPowerKeyTriggered) {
+            final long now = SystemClock.uptimeMillis();
+            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
+                    && now <= mA11yShortcutChordVolumeUpKeyTime
+                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
+                mScreenshotChordVolumeDownKeyConsumed = true;
+                mA11yShortcutChordVolumeUpKeyConsumed = true;
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
+                        ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout());
+            }
+        }
+    }
+
     private long getScreenshotChordLongPressDelay() {
         if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
@@ -1510,13 +1539,15 @@
         mHandler.removeCallbacks(mScreenshotRunnable);
     }
 
+    private void cancelPendingAccessibilityShortcutAction() {
+        mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+    }
+
     private final Runnable mEndCallLongPress = new Runnable() {
         @Override
         public void run() {
             mEndCallKeyHandled = true;
-            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                performAuditoryFeedbackForAccessibilityIfNeed();
-            }
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
             showGlobalActionsInternal();
         }
     };
@@ -1698,7 +1729,8 @@
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
-
+        mAccessibilityShortcutController =
+                new AccessibilityShortcutController(mContext, new Handler());
         // Init display burn-in protection
         boolean burnInProtectionEnabled = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableBurnInProtection);
@@ -2225,8 +2257,7 @@
             }
             lp.format = PixelFormat.TRANSLUCENT;
             lp.setTitle("PointerLocation");
-            WindowManager wm = (WindowManager)
-                    mContext.getSystemService(Context.WINDOW_SERVICE);
+            WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
             lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
             wm.addView(mPointerLocationView, lp);
             mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView);
@@ -2236,7 +2267,7 @@
     private void disablePointerLocation() {
         if (mPointerLocationView != null) {
             mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView);
-            WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+            WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
             wm.removeView(mPointerLocationView);
             mPointerLocationView = null;
         }
@@ -2797,7 +2828,7 @@
     @Override
     public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
-            int logo, int windowFlags, Configuration overrideConfig) {
+            int logo, int windowFlags, Configuration overrideConfig, int displayId) {
         if (!SHOW_SPLASH_SCREENS) {
             return null;
         }
@@ -2898,7 +2929,13 @@
 
             params.setTitle("Splash Screen " + packageName);
 
-            wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+            // Obtain proper context to launch on the right display.
+            final Context displayContext = getDisplayContext(context, displayId);
+            if (displayContext == null) {
+                // Can't show splash screen on requested display, so skip showing at all.
+                return null;
+            }
+            wm = (WindowManager) displayContext.getSystemService(WINDOW_SERVICE);
             view = win.getDecorView();
 
             if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
@@ -2928,6 +2965,24 @@
         return null;
     }
 
+    /** Obtain proper context for showing splash screen on the provided display. */
+    private Context getDisplayContext(Context context, int displayId) {
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            // The default context fits.
+            return context;
+        }
+
+        final DisplayManager dm = (DisplayManager) context.getSystemService(DISPLAY_SERVICE);
+        final Display targetDisplay = dm.getDisplay(displayId);
+        if (targetDisplay == null) {
+            // Failed to obtain the non-default display where splash screen should be shown,
+            // lets not show at all.
+            return null;
+        }
+
+        return context.createDisplayContext(targetDisplay);
+    }
+
     /**
      * Preflight adding a window to the system.
      *
@@ -3251,6 +3306,33 @@
             }
         }
 
+        // If an accessibility shortcut might be partially complete, hold off dispatching until we
+        // know if it is complete or not
+        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable()
+                && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
+            if (mScreenshotChordVolumeDownKeyTriggered ^ mA11yShortcutChordVolumeUpKeyTriggered) {
+                final long now = SystemClock.uptimeMillis();
+                final long timeoutTime = (mScreenshotChordVolumeDownKeyTriggered
+                        ? mScreenshotChordVolumeDownKeyTime : mA11yShortcutChordVolumeUpKeyTime)
+                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
+                if (now < timeoutTime) {
+                    return timeoutTime - now;
+                }
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mScreenshotChordVolumeDownKeyConsumed) {
+                if (!down) {
+                    mScreenshotChordVolumeDownKeyConsumed = false;
+                }
+                return -1;
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
+                if (!down) {
+                    mA11yShortcutChordVolumeUpKeyConsumed = false;
+                }
+                return -1;
+            }
+        }
+
         // Cancel any pending meta actions if we see any other keys being pressed between the down
         // of the meta key and its corresponding up.
         if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
@@ -5760,22 +5842,32 @@
                             mScreenshotChordVolumeDownKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             interceptScreenshotChord();
+                            if (!keyguardActive) {
+                                interceptAccessibilityShortcutChord();
+                            }
                         }
                     } else {
                         mScreenshotChordVolumeDownKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
+                        cancelPendingAccessibilityShortcutAction();
                     }
                 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                     if (down) {
-                        if (interactive && !mScreenshotChordVolumeUpKeyTriggered
+                        if (interactive && !mA11yShortcutChordVolumeUpKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mScreenshotChordVolumeUpKeyTriggered = true;
+                            mA11yShortcutChordVolumeUpKeyTriggered = true;
+                            mA11yShortcutChordVolumeUpKeyTime = event.getDownTime();
+                            mA11yShortcutChordVolumeUpKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             cancelPendingScreenshotChordAction();
+                            if (!keyguardActive) {
+                                interceptAccessibilityShortcutChord();
+                            }
                         }
                     } else {
-                        mScreenshotChordVolumeUpKeyTriggered = false;
+                        mA11yShortcutChordVolumeUpKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
+                        cancelPendingAccessibilityShortcutAction();
                     }
                 }
                 if (down) {
@@ -5863,6 +5955,8 @@
             }
 
             case KeyEvent.KEYCODE_POWER: {
+                // Any activity on the power button stops the accessibility shortcut
+                cancelPendingAccessibilityShortcutAction();
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
                 if (down) {
@@ -7416,31 +7510,11 @@
         }
     }
 
-    private void performAuditoryFeedbackForAccessibilityIfNeed() {
-        if (!isGlobalAccessibilityGestureEnabled()) {
-            return;
-        }
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(
-                Context.AUDIO_SERVICE);
-        if (audioManager.isSilentMode()) {
-            return;
-        }
-        Ringtone ringTone = RingtoneManager.getRingtone(mContext,
-                Settings.System.DEFAULT_NOTIFICATION_URI);
-        ringTone.setStreamType(AudioManager.STREAM_MUSIC);
-        ringTone.play();
-    }
-
     private boolean isTheaterModeEnabled() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.THEATER_MODE_ON, 0) == 1;
     }
 
-    private boolean isGlobalAccessibilityGestureEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
-    }
-
     private boolean areSystemNavigationKeysEnabled() {
         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8aefebc..e1b6c87 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -57,6 +57,7 @@
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -69,6 +70,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.EventLogTags;
+import com.android.server.RescueParty;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
@@ -2549,7 +2551,14 @@
     private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
             final String reason, boolean wait) {
         if (mHandler == null || !mSystemReady) {
-            throw new IllegalStateException("Too early to call shutdown() or reboot()");
+            if (RescueParty.isAttemptingFactoryReset()) {
+                // If we're stuck in a really low-level reboot loop, and a
+                // rescue party is trying to prompt the user for a factory data
+                // reset, we must GET TO DA CHOPPA!
+                PowerManagerService.lowLevelReboot(reason);
+            } else {
+                throw new IllegalStateException("Too early to call shutdown() or reboot()");
+            }
         }
 
         Runnable runnable = new Runnable() {
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index 23be9a3..5a1f473 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -16,79 +16,95 @@
 
 package com.android.server.storage;
 
-import android.annotation.CallSuper;
-import android.annotation.WorkerThread;
-import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-import com.android.internal.os.AppFuseMount;
+import com.android.internal.util.Preconditions;
 import libcore.io.IoUtils;
-
 import java.io.File;
-import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.BlockingQueue;
 
-public class AppFuseBridge implements Runnable {
-    private static final String TAG = AppFuseBridge.class.getSimpleName();
-
-    private final FileDescriptor mDeviceFd;
-    private final FileDescriptor mProxyFd;
-    private final CountDownLatch mMountLatch = new CountDownLatch(1);
+/**
+ * Runnable that delegates FUSE command from the kernel to application.
+ * run() blocks until all opened files on the FUSE mount point are closed. So this should be run in
+ * a separated thread.
+ */
+public class AppFuseBridge implements Runnable, AutoCloseable {
+    public static final String TAG = "AppFuseBridge";
 
     /**
-     * @param deviceFd FD of /dev/fuse. Ownership of fd is taken by AppFuseBridge.
-     * @param proxyFd FD of socket pair. Ownership of fd is taken by AppFuseBridge.
+     * The path AppFuse is mounted to.
+     * The first number is UID who is mounting the FUSE.
+     * THe second number is mount ID.
+     * The path must be sync with vold.
      */
-    private AppFuseBridge(FileDescriptor deviceFd, FileDescriptor proxyFd) {
-        mDeviceFd = deviceFd;
+    private static final String APPFUSE_MOUNT_NAME_TEMPLATE = "/mnt/appfuse/%d_%d";
+
+    private final IMountScope mMountScope;
+    private final ParcelFileDescriptor mProxyFd;
+    private final BlockingQueue<Boolean> mChannel;
+
+    /**
+     * @param mountScope Listener to unmount mount point.
+     * @param proxyFd FD of socket pair. Ownership of FD is taken by AppFuseBridge.
+     * @param channel Channel that the runnable send mount result to.
+     */
+    public AppFuseBridge(
+            IMountScope mountScope, ParcelFileDescriptor proxyFd, BlockingQueue<Boolean> channel) {
+        Preconditions.checkNotNull(mountScope);
+        Preconditions.checkNotNull(proxyFd);
+        Preconditions.checkNotNull(channel);
+        mMountScope = mountScope;
         mProxyFd = proxyFd;
-    }
-
-    public static AppFuseMount startMessageLoop(
-            int uid,
-            String name,
-            FileDescriptor deviceFd,
-            Handler handler,
-            ParcelFileDescriptor.OnCloseListener listener)
-                    throws IOException, ErrnoException, InterruptedException {
-        final FileDescriptor localFd = new FileDescriptor();
-        final FileDescriptor remoteFd = new FileDescriptor();
-        // Needs to specify OsConstants.SOCK_SEQPACKET to keep message boundaries.
-        Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, remoteFd, localFd);
-
-        // Caller must invoke #start() after instantiate AppFuseBridge.
-        // Otherwise FDs will be leaked.
-        final AppFuseBridge bridge = new AppFuseBridge(deviceFd, localFd);
-        final Thread thread = new Thread(bridge, TAG);
-        thread.start();
-        try {
-            bridge.mMountLatch.await();
-        } catch (InterruptedException error) {
-            throw error;
-        }
-        return new AppFuseMount(
-                new File("/mnt/appfuse/" + uid + "_" + name),
-                ParcelFileDescriptor.fromFd(remoteFd, handler, listener));
+        mChannel = channel;
     }
 
     @Override
     public void run() {
-        // deviceFd and proxyFd must be closed in native_start_loop.
-        final int deviceFd = mDeviceFd.getInt$();
-        final int proxyFd = mProxyFd.getInt$();
-        mDeviceFd.setInt$(-1);
-        mProxyFd.setInt$(-1);
-        native_start_loop(deviceFd, proxyFd);
+        try {
+            // deviceFd and proxyFd must be closed in native_start_loop.
+            native_start_loop(
+                    mMountScope.getDeviceFileDescriptor().detachFd(),
+                    mProxyFd.detachFd());
+        } finally {
+            close();
+        }
+    }
+
+    public static ParcelFileDescriptor openFile(int uid, int mountId, int fileId, int mode)
+            throws FileNotFoundException {
+        final File mountPoint = getMountPoint(uid, mountId);
+        try {
+            if (Os.stat(mountPoint.getPath()).st_ino != 1) {
+                throw new FileNotFoundException("Could not find bridge mount point.");
+            }
+        } catch (ErrnoException e) {
+            throw new FileNotFoundException(
+                    "Failed to stat mount point: " + mountPoint.getParent());
+        }
+        return ParcelFileDescriptor.open(new File(mountPoint, String.valueOf(fileId)), mode);
+    }
+
+    private static File getMountPoint(int uid, int mountId) {
+        return new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE,  uid, mountId));
+    }
+
+    @Override
+    public void close() {
+        IoUtils.closeQuietly(mMountScope);
+        IoUtils.closeQuietly(mProxyFd);
+        // Invoke countDown here in case where close is invoked before mount.
+        mChannel.offer(false);
     }
 
     // Used by com_android_server_storage_AppFuse.cpp.
     private void onMount() {
-        mMountLatch.countDown();
+        mChannel.offer(true);
+    }
+
+    public static interface IMountScope extends AutoCloseable {
+        ParcelFileDescriptor getDeviceFileDescriptor();
     }
 
     private native boolean native_start_loop(int deviceFd, int proxyFd);
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 90c711a..a3837b2 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -338,9 +338,11 @@
         mTotalMemory = (long)mDataFileStats.getBlockCount() *
                         mDataFileStats.getBlockSize();
         mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
-        mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
-        mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL);
         mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index e7c5384..6c1648c 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -321,6 +321,19 @@
     }
 
     /**
+     * @see android.service.trust.TrustAgentService#onUnlockLockout(int)
+     */
+    public void onUnlockLockout(int timeoutMs) {
+        try {
+            if (mTrustAgentService != null) {
+                mTrustAgentService.onUnlockLockout(timeoutMs);
+            }
+        } catch (RemoteException e) {
+            onError(e);
+        }
+    }
+
+    /**
      * @see android.service.trust.TrustAgentService#onDeviceLocked()
      */
     public void onDeviceLocked() {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c69b87c..71b725e 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -105,6 +105,7 @@
     private static final int MSG_FLUSH_TRUST_USUALLY_MANAGED = 10;
     private static final int MSG_UNLOCK_USER = 11;
     private static final int MSG_STOP_USER = 12;
+    private static final int MSG_DISPATCH_UNLOCK_LOCKOUT = 13;
 
     private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
 
@@ -335,13 +336,16 @@
 
                 if (!mStrongAuthTracker.canAgentsRunForUser(userInfo.id)) {
                     int flag = mStrongAuthTracker.getStrongAuthForUser(userInfo.id);
-                    if (flag != StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
-                        || !directUnlock) {
-                        if (DEBUG) Slog.d(TAG, "refreshAgentList: skipping user " + userInfo.id
-                            + ": prevented by StrongAuthTracker = 0x"
-                            + Integer.toHexString(mStrongAuthTracker.getStrongAuthForUser(
-                            userInfo.id)));
-                        continue;
+                    if (flag != StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) {
+                        if (flag != StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
+                            || !directUnlock) {
+                            if (DEBUG)
+                                Slog.d(TAG, "refreshAgentList: skipping user " + userInfo.id
+                                    + ": prevented by StrongAuthTracker = 0x"
+                                    + Integer.toHexString(mStrongAuthTracker.getStrongAuthForUser(
+                                    userInfo.id)));
+                            continue;
+                        }
                     }
                 }
 
@@ -650,6 +654,15 @@
         }
     }
 
+    private void dispatchUnlockLockout(int timeoutMs, int userId) {
+        for (int i = 0; i < mActiveAgents.size(); i++) {
+            AgentInfo info = mActiveAgents.valueAt(i);
+            if (info.userId == userId) {
+                info.agent.onUnlockLockout(timeoutMs);
+            }
+        }
+    }
+
     // Listeners
 
     private void addListener(ITrustListener listener) {
@@ -745,6 +758,13 @@
         }
 
         @Override
+        public void reportUnlockLockout(int timeoutMs, int userId) throws RemoteException {
+            enforceReportPermission();
+            mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_LOCKOUT, timeoutMs, userId)
+                    .sendToTarget();
+        }
+
+        @Override
         public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException {
             enforceReportPermission();
             // coalesce refresh messages.
@@ -975,6 +995,9 @@
                 case MSG_DISPATCH_UNLOCK_ATTEMPT:
                     dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
                     break;
+                case MSG_DISPATCH_UNLOCK_LOCKOUT:
+                    dispatchUnlockLockout(msg.arg1, msg.arg2);
+                    break;
                 case MSG_ENABLED_AGENTS_CHANGED:
                     refreshAgentList(UserHandle.USER_ALL);
                     // This is also called when the security mode of a user changes.
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
new file mode 100644
index 0000000..15edaaf
--- /dev/null
+++ b/services/core/java/com/android/server/vr/CompatibilityDisplay.java
@@ -0,0 +1,119 @@
+
+package com.android.server.vr;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.vr.IVrStateCallbacks;
+import android.service.vr.IVrManager;
+import android.util.Log;
+
+import com.android.server.vr.VrManagerService;
+
+/**
+ * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and
+ * render 2D app within a VR experience. For example, bringing up the 2D calculator app in VR.
+ */
+class CompatibilityDisplay {
+    private final static String TAG = "CompatDisplay";
+    private final static boolean DEBUG = false;
+
+    // TODO: Go over these values and figure out what is best
+    private final static int HEIGHT = 960;
+    private final static int WIDTH = 720;
+    private final static int DPI = 320;
+
+    private final DisplayManager mDisplayManager;
+    private final IVrManager mVrManager;
+
+    // TODO: Lock initially created when VrStateCallback was connected through Binder. This may not
+    // be necessary with the direct access to VrManager.
+    private final Object vdLock = new Object();
+
+    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+        @Override
+        public void onVrStateChanged(boolean enabled) {
+            if (enabled != mIsVrModeEnabled) {
+                mIsVrModeEnabled = enabled;
+                if (enabled) {
+                    // TODO: Consider not creating the display until ActivityManager needs one on
+                    // which to display a 2D application.
+                    startVirtualDisplay();
+                } else {
+                    stopVirtualDisplay();
+                }
+            }
+        }
+    };
+
+    private VirtualDisplay mVirtualDisplay;
+    private boolean mIsVrModeEnabled;
+
+    public CompatibilityDisplay(DisplayManager displayManager, IVrManager vrManager) {
+        mDisplayManager = displayManager;
+        mVrManager = vrManager;
+    }
+
+    /**
+     * Initializes the compabilitiy display by listening to VR mode changes.
+     */
+    public void init() {
+        startVrModeListener();
+    }
+
+    private void startVrModeListener() {
+        if (mVrManager != null) {
+            try {
+                mVrManager.registerListener(mVrStateCallbacks);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Could not register VR State listener.", e);
+            }
+        }
+    }
+
+    private void startVirtualDisplay() {
+        if (DEBUG) {
+            Log.d(TAG, "Starting VD, DM:" + mDisplayManager);
+        }
+
+        if (mDisplayManager == null) {
+            Log.w(TAG, "Cannot create virtual display because mDisplayManager == null");
+            return;
+        }
+
+        synchronized (vdLock) {
+            if (mVirtualDisplay != null) {
+                Log.e(TAG, "Starting the virtual display when one already exists", new Exception());
+                return;
+            }
+
+            mVirtualDisplay = mDisplayManager.createVirtualDisplay("VR 2D Display", WIDTH, HEIGHT,
+                    DPI,
+                    null /* Surface */, 0 /* flags */);
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "VD created: " + mVirtualDisplay);
+        }
+    }
+
+    private void stopVirtualDisplay() {
+        if (DEBUG) {
+            Log.i(TAG, "Santos, stopping VD");
+        }
+
+        synchronized (vdLock) {
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.release();
+                mVirtualDisplay = null;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 84cf0c6..57587b0 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -31,6 +31,7 @@
 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;
@@ -51,6 +52,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+
 import com.android.internal.R;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
@@ -136,6 +138,7 @@
     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;
@@ -493,6 +496,11 @@
 
                 mComponentObserver.rebuildAll();
             }
+
+            DisplayManager dm =
+                    (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
+            mCompatibilityDisplay = new CompatibilityDisplay(dm, mVrManager);
+            mCompatibilityDisplay.init();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             synchronized (mLock) {
                 mVrModeAllowed = true;
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 7ba95a4..4fd51b2 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -35,6 +35,7 @@
 import android.provider.Settings;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
+import android.webkit.UserPackage;
 import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewZygote;
@@ -271,21 +272,26 @@
     }
 
     @Override
-    public void setMultiProcessEnabledFromContext(Context context) {
-        boolean enableMultiProcess = false;
-        try {
-            enableMultiProcess = Settings.Global.getInt(context.getContentResolver(),
-                    Settings.Global.WEBVIEW_MULTIPROCESS) == 1;
-        } catch (Settings.SettingNotFoundException ex) {
-        }
-        WebViewZygote.setMultiprocessEnabled(enableMultiProcess);
+    public List<UserPackage> getPackageInfoForProviderAllUsers(Context context,
+            WebViewProviderInfo configInfo) {
+        return UserPackage.getPackageInfosAllUsers(context, configInfo.packageName, PACKAGE_FLAGS);
     }
 
     @Override
-    public void registerContentObserver(Context context, ContentObserver contentObserver) {
-        context.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.WEBVIEW_MULTIPROCESS),
-                false, contentObserver);
+    public int getMultiProcessSetting(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                                      Settings.Global.WEBVIEW_MULTIPROCESS, 0);
+    }
+
+    @Override
+    public void setMultiProcessSetting(Context context, int value) {
+        Settings.Global.putInt(context.getContentResolver(),
+                               Settings.Global.WEBVIEW_MULTIPROCESS, value);
+    }
+
+    @Override
+    public void notifyZygote(boolean enableMultiProcess) {
+        WebViewZygote.setMultiprocessEnabled(enableMultiProcess);
     }
 
     // flags declaring we want extra info from the package manager for webview providers
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index 2d7a998..b06f829 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -20,8 +20,11 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.ContentObserver;
+import android.webkit.UserPackage;
 import android.webkit.WebViewProviderInfo;
 
+import java.util.List;
+
 /**
  * System interface for the WebViewUpdateService.
  * This interface provides a way to test the WebView preparation mechanism - during normal use this
@@ -49,7 +52,16 @@
     public boolean systemIsDebuggable();
     public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
             throws NameNotFoundException;
+    /**
+     * Get the PackageInfos of all users for the package represented by {@param configInfo}.
+     * @return an array of UserPackages for a certain package, each UserPackage being belonging to a
+     *         certain user. The returned array can contain null PackageInfos if the given package
+     *         is uninstalled for some user.
+     */
+    public List<UserPackage> getPackageInfoForProviderAllUsers(Context context,
+            WebViewProviderInfo configInfo);
 
-    public void setMultiProcessEnabledFromContext(Context context);
-    public void registerContentObserver(Context context, ContentObserver contentObserver);
+    public int getMultiProcessSetting(Context context);
+    public void setMultiProcessSetting(Context context, int value);
+    public void notifyZygote(boolean enableMultiProcess);
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 0a7454f..4a105e1 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -94,6 +94,9 @@
                         case Intent.ACTION_USER_ADDED:
                             mImpl.handleNewUser(userId);
                             break;
+                        case Intent.ACTION_USER_REMOVED:
+                            mImpl.handleUserRemoved(userId);
+                            break;
                     }
                 }
         };
@@ -112,6 +115,7 @@
 
         IntentFilter userAddedFilter = new IntentFilter();
         userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
+        userAddedFilter.addAction(Intent.ACTION_USER_REMOVED);
         getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL,
                 userAddedFilter, null /* broadcast permission */, null /* handler */);
 
@@ -261,6 +265,32 @@
             }
         }
 
+        @Override // Binder call
+        public boolean isMultiProcessEnabled() {
+            return WebViewUpdateService.this.mImpl.isMultiProcessEnabled();
+        }
+
+        @Override // Binder call
+        public void enableMultiProcess(boolean enable) {
+            if (getContext().checkCallingPermission(
+                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                String msg = "Permission Denial: enableMultiProcess() from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid()
+                        + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                WebViewUpdateService.this.mImpl.enableMultiProcess(enable);
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
+            }
+        }
+
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 1a77c68..f016830 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -20,12 +20,11 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
-import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.util.Base64;
 import android.util.Slog;
+import android.webkit.UserPackage;
 import android.webkit.WebViewFactory;
 import android.webkit.WebViewProviderInfo;
 import android.webkit.WebViewProviderResponse;
@@ -77,7 +76,6 @@
 
     private SystemInterface mSystemInterface;
     private WebViewUpdater mWebViewUpdater;
-    private SettingsObserver mSettingsObserver;
     final private Context mContext;
 
     public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
@@ -97,41 +95,47 @@
     void prepareWebViewInSystemServer() {
         updateFallbackStateOnBoot();
         mWebViewUpdater.prepareWebViewInSystemServer();
-
-        // Register for changes in the multiprocess developer option. This has to be done
-        // here, since the update service gets created before the ContentResolver service.
-        mSettingsObserver = new SettingsObserver();
+        mSystemInterface.notifyZygote(isMultiProcessEnabled());
     }
 
     private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
         for (WebViewProviderInfo provider : providers) {
             if (provider.availableByDefault && !provider.isFallback) {
-                try {
-                    PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider);
-                    if (isInstalledPackage(packageInfo) && isEnabledPackage(packageInfo)
-                            && mWebViewUpdater.isValidProvider(provider, packageInfo)) {
-                        return true;
-                    }
-                } catch (NameNotFoundException e) {
-                    // A non-existent provider is neither valid nor enabled
+                // userPackages can contain null objects.
+                List<UserPackage> userPackages =
+                        mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider);
+                if (isInstalledAndEnabledForAllUsers(userPackages) &&
+                        // Checking validity of the package for the system user (rather than all
+                        // users) since package validity depends not on the user but on the package
+                        // itself.
+                        mWebViewUpdater.isValidProvider(provider,
+                                userPackages.get(UserHandle.USER_SYSTEM).getPackageInfo())) {
+                    return true;
                 }
             }
         }
         return false;
     }
 
-    /**
-     * Called when a new user has been added to update the state of its fallback package.
-     */
     void handleNewUser(int userId) {
-        if (!mSystemInterface.isFallbackLogicEnabled()) return;
+        handleUserChange();
+    }
 
-        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
-        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
-        if (fallbackProvider == null) return;
+    void handleUserRemoved(int userId) {
+        handleUserChange();
+    }
 
-        mSystemInterface.enablePackageForUser(fallbackProvider.packageName,
-                !existsValidNonFallbackProvider(webviewProviders), userId);
+    /**
+     * Called when a user was added or removed to ensure fallback logic and WebView preparation are
+     * triggered. This has to be done since the WebView package we use depends on the enabled-state
+     * of packages for all users (so adding or removing a user might cause us to change package).
+     */
+    private void handleUserChange() {
+        if (mSystemInterface.isFallbackLogicEnabled()) {
+            updateFallbackState(mSystemInterface.getWebViewPackages());
+        }
+        // Potentially trigger package-changing logic.
+        mWebViewUpdater.updateCurrentWebViewPackage(null);
     }
 
     void notifyRelroCreationCompleted() {
@@ -147,7 +151,7 @@
     }
 
     WebViewProviderInfo[] getValidWebViewPackages() {
-        return mWebViewUpdater.getValidAndInstalledWebViewPackages();
+        return mWebViewUpdater.getValidWebViewPackages();
     }
 
     WebViewProviderInfo[] getWebViewPackages() {
@@ -166,7 +170,7 @@
         if (!mSystemInterface.isFallbackLogicEnabled()) return;
 
         WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
-        updateFallbackState(webviewProviders, true);
+        updateFallbackState(webviewProviders);
     }
 
     /**
@@ -191,35 +195,23 @@
             }
         }
         if (!changedPackageAvailableByDefault) return;
-        updateFallbackState(webviewProviders, false);
+        updateFallbackState(webviewProviders);
     }
 
-    private void updateFallbackState(WebViewProviderInfo[] webviewProviders, boolean isBoot) {
+    private void updateFallbackState(WebViewProviderInfo[] webviewProviders) {
         // If there exists a valid and enabled non-fallback package - disable the fallback
         // package, otherwise, enable it.
         WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
         if (fallbackProvider == null) return;
         boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
 
-        boolean isFallbackEnabled = false;
-        try {
-            isFallbackEnabled = isEnabledPackage(
-                    mSystemInterface.getPackageInfoForProvider(fallbackProvider));
-        } catch (NameNotFoundException e) {
-            // No fallback package installed -> early out.
-            return;
-        }
-
-        if (existsValidNonFallbackProvider
-                // During an OTA the primary user's WebView state might differ from other users', so
-                // ignore the state of that user during boot.
-                && (isFallbackEnabled || isBoot)) {
+        List<UserPackage> userPackages =
+                mSystemInterface.getPackageInfoForProviderAllUsers(mContext, fallbackProvider);
+        if (existsValidNonFallbackProvider && !isDisabledForAllUsers(userPackages)) {
             mSystemInterface.uninstallAndDisablePackageForAllUsers(mContext,
                     fallbackProvider.packageName);
         } else if (!existsValidNonFallbackProvider
-                // During an OTA the primary user's WebView state might differ from other users', so
-                // ignore the state of that user during boot.
-                && (!isFallbackEnabled || isBoot)) {
+                && !isInstalledAndEnabledForAllUsers(userPackages)) {
             // Enable the fallback package for all users.
             mSystemInterface.enablePackageForAllUsers(mContext,
                     fallbackProvider.packageName, true);
@@ -247,6 +239,19 @@
                 && packageName.equals(fallbackProvider.packageName));
     }
 
+    boolean isMultiProcessEnabled() {
+        return mSystemInterface.getMultiProcessSetting(mContext) != 0;
+    }
+
+    void enableMultiProcess(boolean enable) {
+        PackageInfo current = getCurrentWebViewPackage();
+        mSystemInterface.setMultiProcessSetting(mContext, enable ? 1 : 0);
+        mSystemInterface.notifyZygote(enable);
+        if (current != null) {
+            mSystemInterface.killPackageDependents(current.packageName);
+        }
+    }
+
     /**
      * Class that decides what WebView implementation to use and prepares that implementation for
      * use.
@@ -369,38 +374,8 @@
          * or the replacement are done).
          */
         public String changeProviderAndSetting(String newProviderName) {
-            PackageInfo oldPackage = null;
-            PackageInfo newPackage = null;
-            boolean providerChanged = false;
-            synchronized(mLock) {
-                oldPackage = mCurrentWebViewPackage;
-                mSystemInterface.updateUserSetting(mContext, newProviderName);
-
-                try {
-                    newPackage = findPreferredWebViewPackage();
-                    providerChanged = (oldPackage == null)
-                            || !newPackage.packageName.equals(oldPackage.packageName);
-                } catch (WebViewPackageMissingException e) {
-                    mCurrentWebViewPackage = null;
-                    Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
-                            "package " + e);
-                    // If we don't perform the user change but don't have an installed WebView
-                    // package, we will have changed the setting and it will be used when a package
-                    // is available.
-                    return "";
-                }
-                // Perform the provider change if we chose a new provider
-                if (providerChanged) {
-                    onWebViewProviderChanged(newPackage);
-                }
-            }
-            // Kill apps using the old provider only if we changed provider
-            if (providerChanged && oldPackage != null) {
-                mSystemInterface.killPackageDependents(oldPackage.packageName);
-            }
-            // Return the new provider, this is not necessarily the one we were asked to switch to
-            // But the persistent setting will now be pointing to the provider we were asked to
-            // switch to anyway
+            PackageInfo newPackage = updateCurrentWebViewPackage(newProviderName);
+            if (newPackage == null) return "";
             return newPackage.packageName;
         }
 
@@ -430,15 +405,14 @@
             }
         }
 
-        private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos(boolean onlyInstalled) {
+        private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
             WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages();
             List<ProviderAndPackageInfo> providers = new ArrayList<>();
             for(int n = 0; n < allProviders.length; n++) {
                 try {
                     PackageInfo packageInfo =
                         mSystemInterface.getPackageInfoForProvider(allProviders[n]);
-                    if ((!onlyInstalled || isInstalledPackage(packageInfo))
-                            && isValidProvider(allProviders[n], packageInfo)) {
+                    if (isValidProvider(allProviders[n], packageInfo)) {
                         providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
                     }
                 } catch (NameNotFoundException e) {
@@ -451,9 +425,8 @@
         /**
          * Fetch only the currently valid WebView packages.
          **/
-        public WebViewProviderInfo[] getValidAndInstalledWebViewPackages() {
-            ProviderAndPackageInfo[] providersAndPackageInfos =
-                getValidWebViewPackagesAndInfos(true /* only fetch installed packages */);
+        public WebViewProviderInfo[] getValidWebViewPackages() {
+            ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
             WebViewProviderInfo[] providers =
                 new WebViewProviderInfo[providersAndPackageInfos.length];
             for(int n = 0; n < providersAndPackageInfos.length; n++) {
@@ -480,39 +453,49 @@
          *
          */
         private PackageInfo findPreferredWebViewPackage() throws WebViewPackageMissingException {
-            ProviderAndPackageInfo[] providers =
-                getValidWebViewPackagesAndInfos(false /* onlyInstalled */);
+            ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
 
             String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(mContext);
 
-            // If the user has chosen provider, use that
+            // If the user has chosen provider, use that (if it's installed and enabled for all
+            // users).
             for (ProviderAndPackageInfo providerAndPackage : providers) {
-                if (providerAndPackage.provider.packageName.equals(userChosenProvider)
-                        && isInstalledPackage(providerAndPackage.packageInfo)
-                        && isEnabledPackage(providerAndPackage.packageInfo)) {
-                    return providerAndPackage.packageInfo;
+                if (providerAndPackage.provider.packageName.equals(userChosenProvider)) {
+                    // userPackages can contain null objects.
+                    List<UserPackage> userPackages =
+                            mSystemInterface.getPackageInfoForProviderAllUsers(mContext,
+                                    providerAndPackage.provider);
+                    if (isInstalledAndEnabledForAllUsers(userPackages)) {
+                        return providerAndPackage.packageInfo;
+                    }
                 }
             }
 
             // User did not choose, or the choice failed; use the most stable provider that is
-            // installed and enabled for the device owner, and available by default (not through
+            // installed and enabled for all users, and available by default (not through
             // user choice).
             for (ProviderAndPackageInfo providerAndPackage : providers) {
-                if (providerAndPackage.provider.availableByDefault
-                        && isInstalledPackage(providerAndPackage.packageInfo)
-                        && isEnabledPackage(providerAndPackage.packageInfo)) {
-                    return providerAndPackage.packageInfo;
+                if (providerAndPackage.provider.availableByDefault) {
+                    // userPackages can contain null objects.
+                    List<UserPackage> userPackages =
+                            mSystemInterface.getPackageInfoForProviderAllUsers(mContext,
+                                    providerAndPackage.provider);
+                    if (isInstalledAndEnabledForAllUsers(userPackages)) {
+                        return providerAndPackage.packageInfo;
+                    }
                 }
             }
 
             // Could not find any installed and enabled package either, use the most stable and
             // default-available provider.
+            // TODO(gsennton) remove this when we have a functional WebView stub.
             for (ProviderAndPackageInfo providerAndPackage : providers) {
                 if (providerAndPackage.provider.availableByDefault) {
                     return providerAndPackage.packageInfo;
                 }
             }
 
+            // This should never happen during normal operation (only with modified system images).
             mAnyWebViewInstalled = false;
             throw new WebViewPackageMissingException("Could not find a loadable WebView package");
         }
@@ -695,6 +678,48 @@
                         mAnyWebViewInstalled));
             }
         }
+
+        /**
+         * Update the current WebView package.
+         * @param newProviderName the package to switch to, null if no package has been explicitly
+         * chosen.
+         */
+        public PackageInfo updateCurrentWebViewPackage(String newProviderName) {
+            PackageInfo oldPackage = null;
+            PackageInfo newPackage = null;
+            boolean providerChanged = false;
+            synchronized(mLock) {
+                oldPackage = mCurrentWebViewPackage;
+
+                if (newProviderName != null) {
+                    mSystemInterface.updateUserSetting(mContext, newProviderName);
+                }
+
+                try {
+                    newPackage = findPreferredWebViewPackage();
+                    providerChanged = (oldPackage == null)
+                            || !newPackage.packageName.equals(oldPackage.packageName);
+                } catch (WebViewPackageMissingException e) {
+                    // If updated the Setting but don't have an installed WebView package, the
+                    // Setting will be used when a package is available.
+                    mCurrentWebViewPackage = null;
+                    Slog.e(TAG, "Couldn't find WebView package to use " + e);
+                    return null;
+                }
+                // Perform the provider change if we chose a new provider
+                if (providerChanged) {
+                    onWebViewProviderChanged(newPackage);
+                }
+            }
+            // Kill apps using the old provider only if we changed provider
+            if (providerChanged && oldPackage != null) {
+                mSystemInterface.killPackageDependents(oldPackage.packageName);
+            }
+            // Return the new provider, this is not necessarily the one we were asked to switch to,
+            // but the persistent setting will now be pointing to the provider we were asked to
+            // switch to anyway.
+            return newPackage;
+        }
     }
 
     private static boolean providerHasValidSignature(WebViewProviderInfo provider,
@@ -723,45 +748,27 @@
     }
 
     /**
-     * Returns whether the given package is enabled.
-     * This state can be changed by the user from Settings->Apps
+     * Return true iff {@param packageInfos} point to only installed and enabled packages.
+     * The given packages {@param packageInfos} should all be pointing to the same package, but each
+     * PackageInfo representing a different user's package.
      */
-    private static boolean isEnabledPackage(PackageInfo packageInfo) {
-        return packageInfo.applicationInfo.enabled;
+    private static boolean isInstalledAndEnabledForAllUsers(
+            List<UserPackage> userPackages) {
+        for (UserPackage userPackage : userPackages) {
+            if (!userPackage.isInstalledPackage() || !userPackage.isEnabledPackage()) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    /**
-     * Return true if the package is installed and not hidden
-     */
-    private static boolean isInstalledPackage(PackageInfo packageInfo) {
-        return (((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
-            && ((packageInfo.applicationInfo.privateFlags
-                        & ApplicationInfo.PRIVATE_FLAG_HIDDEN) == 0));
-    }
-
-    /**
-     * Watches for changes in the WEBVIEW_MULTIPROCESS setting and lets
-     * the WebViewZygote know, so it can start or stop the zygote process
-     * appropriately.
-     */
-    private class SettingsObserver extends ContentObserver {
-        SettingsObserver() {
-            super(new Handler());
-
-            mSystemInterface.registerContentObserver(mContext, this);
-
-            // Push the current value of the setting immediately.
-            notifyZygote();
+    private static boolean isDisabledForAllUsers(List<UserPackage> userPackages) {
+        for (UserPackage userPackage : userPackages) {
+            if (userPackage.getPackageInfo() != null && userPackage.isEnabledPackage()) {
+                return false;
+            }
         }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            notifyZygote();
-        }
-
-        private void notifyZygote() {
-            mSystemInterface.setMultiProcessEnabledFromContext(mContext);
-        }
+        return true;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index a900702..0436139 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -87,7 +87,6 @@
 
     private final Runnable mRemoveStartingWindow = () -> {
         StartingSurface surface = null;
-        StartingData data = null;
         synchronized (mWindowMap) {
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
                     + ": startingWindow=" + mContainer.startingWindow
@@ -97,14 +96,13 @@
             }
             if (mContainer.startingWindow != null) {
                 surface = mContainer.startingSurface;
-                data = mContainer.startingData;
                 mContainer.startingData = null;
                 mContainer.startingSurface = null;
                 mContainer.startingWindow = null;
                 mContainer.startingDisplayed = false;
             }
         }
-        if (data != null && surface != null) {
+        if (surface != null) {
             try {
                 surface.remove();
             } catch (Exception e) {
@@ -115,12 +113,14 @@
 
     private final Runnable mAddStartingWindow = () -> {
         final StartingData startingData;
+        final AppWindowToken container;
 
         synchronized (mWindowMap) {
             if (mContainer == null) {
                 return;
             }
             startingData = mContainer.startingData;
+            container = mContainer;
         }
 
         if (startingData == null) {
@@ -129,41 +129,40 @@
         }
 
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
-                + this + ": startingData=" + mContainer.startingData);
+                + this + ": startingData=" + container.startingData);
 
         StartingSurface surface = null;
         try {
-            surface = startingData.createStartingSurface();
+            surface = startingData.createStartingSurface(container);
         } catch (Exception e) {
             Slog.w(TAG_WM, "Exception when adding starting window", e);
         }
         if (surface != null) {
             boolean abort = false;
             synchronized(mWindowMap) {
-                if (mContainer.removed || mContainer.startingData == null) {
+                if (container.removed || container.startingData == null) {
                     // If the window was successfully added, then
                     // we need to remove it.
-                    if (mContainer.startingWindow != null) {
+                    if (container.startingWindow != null) {
                         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                                "Aborted starting " + mContainer
-                                        + ": removed=" + mContainer.removed
-                                        + " startingData=" + mContainer.startingData);
+                                "Aborted starting " + container
+                                        + ": removed=" + container.removed
+                                        + " startingData=" + container.startingData);
+                        container.startingWindow = null;
+                        container.startingData = null;
                         abort = true;
                     }
                 } else {
-                    mContainer.startingSurface = surface;
+                    container.startingSurface = surface;
                 }
                 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
                         "Added starting " + mContainer
                                 + ": startingWindow="
-                                + mContainer.startingWindow + " startingView="
-                                + mContainer.startingSurface);
+                                + container.startingWindow + " startingView="
+                                + container.startingSurface);
             }
             if (abort) {
-                mRemoveStartingWindow.run();
-            if (mContainer == null) {
-                return;
-            }
+                surface.remove();
             }
         }
     };
@@ -465,7 +464,7 @@
             }
 
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
-            mContainer.startingData = new SplashScreenStartingData(mService, mContainer, pkg, theme,
+            mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
                     compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                     mContainer.getMergedOverrideConfiguration());
             scheduleAddStartingWindow();
@@ -493,14 +492,13 @@
 
     private boolean createSnapshot() {
         final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
-                mContainer.mTask);
+                mContainer.mTask.mTaskId, mContainer.mTask.mUserId, false /* restoreFromDisk */);
 
         if (snapshot == null) {
             return false;
         }
 
-        mContainer.startingData = new SnapshotStartingData(mService, mContainer,
-                snapshot.getSnapshot());
+        mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
         scheduleAddStartingWindow();
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 10d1d8b..ac9859d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -445,6 +445,7 @@
 
         mService.mOpeningApps.remove(this);
         mService.mUnknownAppVisibilityController.appRemoved(this);
+        mService.mTaskSnapshotController.onAppRemoved(this);
         waitingToShow = false;
         if (mService.mClosingApps.contains(this)) {
             delayed = true;
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index b99dda1..015c084 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -77,6 +77,8 @@
         boolean dimFullscreen();
         /** Returns the display info. of the dim layer user. */
         DisplayInfo getDisplayInfo();
+        /** Returns true if the dim layer user is currently attached to a display */
+        boolean isAttachedToDisplay();
         /** Gets the bounds of the dim layer user. */
         void getDimBounds(Rect outBounds);
         String toShortString();
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 04ae72f..2ec2dba 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -191,8 +191,21 @@
         boolean result = false;
 
         for (int i = mState.size() - 1; i >= 0; i--) {
-            DimLayer.DimLayerUser user = mState.keyAt(i);
-            DimLayerState state = mState.valueAt(i);
+            final DimLayer.DimLayerUser user = mState.keyAt(i);
+            final DimLayerState state = mState.valueAt(i);
+
+            if (!user.isAttachedToDisplay()) {
+                // Leaked dim user that is no longer attached to the display. Go ahead and clean it
+                // clean-up and log what happened.
+                // TODO: This is a work around for b/34395537 as the dim user should have cleaned-up
+                // it self when it was detached from the display. Need to investigate how the dim
+                // user is leaking...
+                Slog.wtfStack(TAG_WM, "Leaked dim user=" + user.toShortString()
+                        + " state=" + state);
+                removeDimLayerUser(user);
+                continue;
+            }
+
             // We have to check that we are actually the shared fullscreen layer
             // for this path. If we began as non fullscreen and became fullscreen
             // (e.g. Docked stack closing), then we may not be the shared layer
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 47003fa..3958510 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1437,6 +1437,12 @@
         return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
     }
 
+    /** Checks if stack with provided id is visible on this display. */
+    boolean isStackVisible(int stackId) {
+        final TaskStack stack = getStackById(stackId);
+        return (stack != null && stack.isVisible());
+    }
+
     /**
      * @return The docked stack, but only if it is visible, and {@code null} otherwise.
      */
@@ -1482,6 +1488,13 @@
 
     boolean canAddToastWindowForUid(int uid) {
         // We allow one toast window per UID being shown at a time.
+        // Also if the app is focused adding more than one toast at
+        // a time for better backwards compatibility.
+        final WindowState focusedWindowForUid = getWindow(w ->
+                w.mOwnerUid == uid && w.isFocused());
+        if (focusedWindowForUid != null) {
+            return true;
+        }
         final WindowState win = getWindow(w ->
                 w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == uid && !w.mPermanentlyHidden
                 && !w.mWindowRemovalAllowed);
@@ -2246,10 +2259,11 @@
                 }
 
                 // Don't include wallpaper in bounds calculation
-                if (includeDecor && !stackBounds.isEmpty()) {
-                    frame.set(stackBounds);
-                } else if (includeDecor) {
-                    mutableIncludeFullDisplay.value = true;
+                if (!mutableIncludeFullDisplay.value && includeDecor) {
+                    final TaskStack stack = w.getStack();
+                    if (stack != null) {
+                        stack.getBounds(frame);
+                    }
                 } else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
                     final Rect wf = w.mFrame;
                     final Rect cr = w.mContentInsets;
@@ -2565,9 +2579,7 @@
                     : requestedPosition >= topChildPosition;
             int targetPosition = requestedPosition;
 
-            if (toTop
-                    && mService.isStackVisibleLocked(PINNED_STACK_ID)
-                    && stack.mStackId != PINNED_STACK_ID) {
+            if (toTop && isStackVisible(PINNED_STACK_ID) && stack.mStackId != PINNED_STACK_ID) {
                 // The pinned stack is always the top most stack (always-on-top) when it is visible.
                 TaskStack topStack = mChildren.get(topChildPosition);
                 if (topStack.mStackId != PINNED_STACK_ID) {
@@ -2577,8 +2589,8 @@
                 // So, stack is moved just below the pinned stack.
                 // When we're adding a new stack the target is the current pinned stack position.
                 // When we're positioning an existing stack the target is the position below pinned
-                // stack, because WindowContainer#positionAt() first removes element and then adds it
-                // to specified place.
+                // stack, because WindowContainer#positionAt() first removes element and then adds
+                // it to specified place.
                 targetPosition = adding ? topChildPosition : topChildPosition - 1;
             }
 
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index e6bc7f4..ed1e2d9 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -835,6 +835,11 @@
     }
 
     @Override
+    public boolean isAttachedToDisplay() {
+        return mDisplayContent != null;
+    }
+
+    @Override
     public void getDimBounds(Rect outBounds) {
         // This dim layer user doesn't need this.
     }
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 34633c2..08f9b45 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -82,6 +82,7 @@
 
     // Used to calculate stack bounds across rotations
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
+    private final Rect mStableInsets = new Rect();
 
     // The size and position information that describes where the pinned stack will go by default.
     private int mDefaultStackGravity;
@@ -250,10 +251,12 @@
     }
 
     /**
-     * @return the repositioned PIP bounds given it's pre-change bounds, and the new display info.
+     * @return the repositioned PIP bounds given it's pre-change bounds, and the new display
+     *         content.
      */
-    Rect onDisplayChanged(Rect preChangeStackBounds, DisplayInfo displayInfo) {
+    Rect onDisplayChanged(Rect preChangeStackBounds, DisplayContent displayContent) {
         final Rect postChangeStackBounds = new Rect(preChangeStackBounds);
+        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (!mDisplayInfo.equals(displayInfo)) {
             // Calculate the snap fraction of the current stack along the old movement bounds, and
             // then update the stack bounds to the same fraction along the rotated movement bounds.
@@ -269,8 +272,9 @@
             if (mIsMinimized) {
                 final Point displaySize = new Point(mDisplayInfo.logicalWidth,
                         mDisplayInfo.logicalHeight);
+                mService.getStableInsetsLocked(displayContent.getDisplayId(), mStableInsets);
                 mSnapAlgorithm.applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds,
-                        displaySize);
+                        displaySize, mStableInsets);
             }
         }
         return postChangeStackBounds;
@@ -329,7 +333,9 @@
      */
     void setActions(List<RemoteAction> actions) {
         mActions.clear();
-        mActions.addAll(actions);
+        if (actions != null) {
+            mActions.addAll(actions);
+        }
         notifyActionsChanged(mActions);
     }
 
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index 9d97a0c..e73d4d2 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -27,16 +27,14 @@
     private final WindowManagerService mService;
     private final GraphicBuffer mSnapshot;
 
-    SnapshotStartingData(WindowManagerService service, AppWindowToken appWindowToken,
-            GraphicBuffer snapshot) {
-        super(service, appWindowToken);
+    SnapshotStartingData(WindowManagerService service, GraphicBuffer snapshot) {
+        super(service);
         mService = service;
         mSnapshot = snapshot;
     }
 
     @Override
-    StartingSurface createStartingSurface() {
-        return mService.mTaskSnapshotController.createStartingSurface(
-                mAppWindowToken, mSnapshot);
+    StartingSurface createStartingSurface(AppWindowToken atoken) {
+        return mService.mTaskSnapshotController.createStartingSurface(atoken, mSnapshot);
     }
 }
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
index 664e600..4b14f86 100644
--- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -35,11 +35,10 @@
     private final int mWindowFlags;
     private final Configuration mMergedOverrideConfiguration;
 
-    SplashScreenStartingData(WindowManagerService service, AppWindowToken appWindowToken,
-            String pkg, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel,
-            int labelRes, int icon, int logo, int windowFlags,
-            Configuration mergedOverrideConfiguration) {
-        super(service, appWindowToken);
+    SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
+            CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
+            int logo, int windowFlags, Configuration mergedOverrideConfiguration) {
+        super(service);
         mPkg = pkg;
         mTheme = theme;
         mCompatInfo = compatInfo;
@@ -52,9 +51,9 @@
     }
 
     @Override
-    StartingSurface createStartingSurface() {
-        return mService.mPolicy.addSplashScreen(mAppWindowToken.token, mPkg, mTheme, mCompatInfo,
+    StartingSurface createStartingSurface(AppWindowToken atoken) {
+        return mService.mPolicy.addSplashScreen(atoken.token, mPkg, mTheme, mCompatInfo,
                 mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
-                mMergedOverrideConfiguration);
+                mMergedOverrideConfiguration, atoken.getDisplayContent().getDisplayId());
     }
 }
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index fcc4c3c..8c564bb 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -24,19 +24,18 @@
 public abstract class StartingData {
 
     protected final WindowManagerService mService;
-    protected final AppWindowToken mAppWindowToken;
 
-    protected StartingData(WindowManagerService service, AppWindowToken appWindowToken) {
+    protected StartingData(WindowManagerService service) {
         mService = service;
-        mAppWindowToken = appWindowToken;
     }
 
     /**
      * Creates the actual starting window surface. DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING
      * THIS METHOD.
      *
+     * @param atoken the app to add the starting window to
      * @return a class implementing {@link StartingSurface} for easy removal with
      *         {@link StartingSurface#remove}
      */
-    abstract StartingSurface createStartingSurface();
+    abstract StartingSurface createStartingSurface(AppWindowToken atoken);
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2d50e3a..680d0f2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -186,8 +186,18 @@
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
+        final DisplayContent prevDisplayContent = getDisplayContent();
+
         getParent().removeChild(this);
         stack.addTask(this, position, showForAllUsers(), false /* moveParents */);
+
+        // Relayout display(s).
+        final DisplayContent displayContent = stack.getDisplayContent();
+        displayContent.setLayoutNeeded();
+        if (prevDisplayContent != displayContent) {
+            onDisplayChanged(displayContent);
+            prevDisplayContent.setLayoutNeeded();
+        }
     }
 
     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
@@ -618,7 +628,12 @@
 
     @Override
     public DisplayInfo getDisplayInfo() {
-        return mStack.getDisplayContent().getDisplayInfo();
+        return getDisplayContent().getDisplayInfo();
+    }
+
+    @Override
+    public boolean isAttachedToDisplay() {
+        return getDisplayContent() != null;
     }
 
     void forceWindowsScaleable(boolean force) {
@@ -638,6 +653,11 @@
     }
 
     @Override
+    TaskWindowContainerController getController() {
+        return (TaskWindowContainerController) super.getController();
+    }
+
+    @Override
     public String toString() {
         return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
     }
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 267566b..7bc577e 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -693,6 +693,11 @@
     }
 
     @Override
+    public boolean isAttachedToDisplay() {
+        return mTask != null && mTask.getDisplayContent() != null;
+    }
+
+    @Override
     public void getDimBounds(Rect out) {
         // This dim layer user doesn't need this.
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index 994a155..601bf28 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -19,6 +19,11 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager.TaskSnapshot;
 import android.util.ArrayMap;
+import android.util.LruCache;
+
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Map.Entry;
 
 /**
  * Caches snapshots. See {@link TaskSnapshotController}.
@@ -27,13 +32,139 @@
  */
 class TaskSnapshotCache {
 
-    private final ArrayMap<Task, TaskSnapshot> mCache = new ArrayMap<>();
+    // TODO: Make this more dynamic to accomodate for different clients.
+    private static final int RETRIEVAL_CACHE_SIZE = 4;
 
-    void putSnapshot(Task task, TaskSnapshot snapshot) {
-        mCache.put(task, snapshot);
+    private final WindowManagerService mService;
+    private final TaskSnapshotLoader mLoader;
+    private final ArrayMap<AppWindowToken, Integer> mAppTaskMap = new ArrayMap<>();
+    private final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>();
+    private final LruCache<Integer, TaskSnapshot> mRetrievalCache =
+            new LruCache<>(RETRIEVAL_CACHE_SIZE);
+
+    TaskSnapshotCache(WindowManagerService service, TaskSnapshotLoader loader) {
+        mService = service;
+        mLoader = loader;
     }
 
-    @Nullable TaskSnapshot getSnapshot(Task task) {
-        return mCache.get(task);
+    void putSnapshot(Task task, TaskSnapshot snapshot) {
+        final CacheEntry entry = mRunningCache.get(task.mTaskId);
+        if (entry != null) {
+            mAppTaskMap.remove(entry.topApp);
+        }
+        final AppWindowToken top = task.getTopChild();
+        mAppTaskMap.put(top, task.mTaskId);
+        mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, task.getTopChild()));
+        mRetrievalCache.put(task.mTaskId, snapshot);
+    }
+
+    /**
+     * If {@param restoreFromDisk} equals {@code true}, DO NOT HOLD THE WINDOW MANAGER LOCK!
+     */
+    @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk) {
+
+        synchronized (mService.mWindowMap) {
+            // Try the running cache.
+            final CacheEntry entry = mRunningCache.get(taskId);
+            if (entry != null) {
+                return entry.snapshot;
+            }
+
+            // Try the retrieval cache.
+            final TaskSnapshot snapshot = mRetrievalCache.get(taskId);
+            if (snapshot != null) {
+                return snapshot;
+            }
+        }
+
+        // Try to restore from disk if asked.
+        if (!restoreFromDisk) {
+            return null;
+        }
+        return tryRestoreFromDisk(taskId, userId);
+    }
+
+    /**
+     * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING THIS METHOD!
+     */
+    private TaskSnapshot tryRestoreFromDisk(int taskId, int userId) {
+        final TaskSnapshot snapshot = mLoader.loadTask(taskId, userId);
+        if (snapshot == null) {
+            return null;
+        }
+        synchronized (mService.mWindowMap) {
+            mRetrievalCache.put(taskId, snapshot);
+        }
+        return snapshot;
+    }
+
+    /**
+     * Called when an app token has been removed
+     */
+    void onAppRemoved(AppWindowToken wtoken) {
+        final Integer taskId = mAppTaskMap.get(wtoken);
+        if (taskId != null) {
+            removeRunningEntry(taskId);
+        }
+        if (wtoken.mTask != null) {
+            mRetrievalCache.remove(wtoken.mTask.mTaskId);
+        }
+    }
+
+    /**
+     * Callend when an app window token's process died.
+     */
+    void onAppDied(AppWindowToken wtoken) {
+        final Integer taskId = mAppTaskMap.get(wtoken);
+        if (taskId != null) {
+            removeRunningEntry(taskId);
+        }
+    }
+
+    void onTaskRemoved(int taskId) {
+        removeRunningEntry(taskId);
+        mRetrievalCache.remove(taskId);
+    }
+
+    private void removeRunningEntry(int taskId) {
+        final CacheEntry entry = mRunningCache.get(taskId);
+        if (entry != null) {
+            mAppTaskMap.remove(entry.topApp);
+            mRunningCache.remove(taskId);
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        final String doublePrefix = prefix + "  ";
+        final String triplePrefix = doublePrefix + "  ";
+        final String quadruplePrefix = triplePrefix + "  ";
+        pw.println(prefix + "SnapshotCache");
+        pw.println(doublePrefix + "RunningCache");
+        for (int i = mRunningCache.size() - 1; i >= 0; i--) {
+            final CacheEntry entry = mRunningCache.valueAt(i);
+            pw.println(triplePrefix + "Entry taskId=" + mRunningCache.keyAt(i));
+            pw.println(quadruplePrefix + "topApp=" + entry.topApp);
+            pw.println(quadruplePrefix + "snapshot=" + entry.snapshot);
+        }
+        pw.println(doublePrefix + "RetrievalCache");
+        final Map<Integer, TaskSnapshot> retrievalSnapshot = mRetrievalCache.snapshot();
+        for (Entry<Integer, TaskSnapshot> entry : retrievalSnapshot.entrySet()) {
+            pw.println(triplePrefix + "Entry taskId=" + entry.getKey());
+            pw.println(quadruplePrefix + "snapshot=" + entry.getValue());
+        }
+    }
+
+    private static final class CacheEntry {
+
+        /** The snapshot. */
+        final TaskSnapshot snapshot;
+
+        /** The app token that was on top of the task when the snapshot was taken */
+        final AppWindowToken topApp;
+
+        CacheEntry(TaskSnapshot snapshot, AppWindowToken topApp) {
+            this.snapshot = snapshot;
+            this.topApp = topApp;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 68aceae..15878f6 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,23 +17,19 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
-import static android.graphics.Bitmap.Config.ARGB_8888;
-import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
-import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
-import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
-import static android.graphics.PixelFormat.RGBA_8888;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskSnapshot;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
+import android.os.Environment;
 import android.util.ArraySet;
 import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.PrintWriter;
+
 /**
  * When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
  * put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we
@@ -50,12 +46,20 @@
 class TaskSnapshotController {
 
     private final WindowManagerService mService;
-    private final TaskSnapshotCache mCache = new TaskSnapshotCache();
 
+    private final TaskSnapshotCache mCache;
+    private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
+            Environment::getDataSystemCeDirectory);
+    private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
     private final ArraySet<Task> mTmpTasks = new ArraySet<>();
 
     TaskSnapshotController(WindowManagerService service) {
         mService = service;
+        mCache = new TaskSnapshotCache(mService, mLoader);
+    }
+
+    void systemReady() {
+        mPersister.start();
     }
 
     void onTransitionStarting() {
@@ -74,12 +78,20 @@
             final TaskSnapshot snapshot = snapshotTask(task);
             if (snapshot != null) {
                 mCache.putSnapshot(task, snapshot);
+                mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                if (task.getController() != null) {
+                    task.getController().reportSnapshotChanged(snapshot);
+                }
             }
         }
     }
 
-    @Nullable TaskSnapshot getSnapshot(Task task) {
-        return mCache.getSnapshot(task);
+    /**
+     * Retrieves a snapshot. If {@param restoreFromDisk} equals {@code true}, DO HOLD THE WINDOW
+     * MANAGER LOCK WHEN CALLING THIS METHOD!
+     */
+    @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk) {
+        return mCache.getSnapshot(taskId, userId, restoreFromDisk);
     }
 
     /**
@@ -92,7 +104,7 @@
     }
 
     private TaskSnapshot snapshotTask(Task task) {
-        final AppWindowToken top = (AppWindowToken) task.getTop();
+        final AppWindowToken top = task.getTopChild();
         if (top == null) {
             return null;
         }
@@ -125,4 +137,34 @@
     private boolean canSnapshotTask(Task task) {
         return !StackId.isHomeOrRecentsStack(task.mStack.mStackId);
     }
+
+    /**
+     * Called when an {@link AppWindowToken} has been removed.
+     */
+    void onAppRemoved(AppWindowToken wtoken) {
+        mCache.onAppRemoved(wtoken);
+    }
+
+    /**
+     * Called when the process of an {@link AppWindowToken} has died.
+     */
+    void onAppDied(AppWindowToken wtoken) {
+        mCache.onAppDied(wtoken);
+    }
+
+    void notifyTaskRemovedFromRecents(int taskId, int userId) {
+        mCache.onTaskRemoved(taskId);
+        mPersister.onTaskRemovedFromRecents(taskId, userId);
+    }
+
+    /**
+     * See {@link TaskSnapshotPersister#removeObsoleteFiles}
+     */
+    void removeObsoleteTaskFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
+        mPersister.removeObsoleteFiles(persistentTaskIds, runningUserIds);
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        mCache.dump(pw, prefix);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
new file mode 100644
index 0000000..4340822
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -0,0 +1,93 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
+import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
+import android.util.Slog;
+
+import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+/**
+ * Loads a persisted {@link TaskSnapshot} from disk.
+ * <p>
+ * Do not hold the window manager lock when accessing this class.
+ * <p>
+ * Test class: {@link TaskSnapshotPersisterLoaderTest}
+ */
+class TaskSnapshotLoader {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotLoader" : TAG_WM;
+
+    private final TaskSnapshotPersister mPersister;
+
+    TaskSnapshotLoader(TaskSnapshotPersister persister) {
+        mPersister = persister;
+    }
+
+    /**
+     * Loads a task from the disk.
+     * <p>
+     * Do not hold the window manager lock when calling this method, as we directly read data from
+     * disk here, which might be slow.
+     *
+     * @param taskId The id of the task to load.
+     * @param userId The id of the user the task belonged to.
+     * @return The loaded {@link TaskSnapshot} or {@code null} if it couldn't be loaded.
+     */
+    TaskSnapshot loadTask(int taskId, int userId) {
+        final File protoFile = mPersister.getProtoFile(taskId, userId);
+        final File bitmapFile = mPersister.getBitmapFile(taskId, userId);
+        if (!protoFile.exists() || !bitmapFile.exists()) {
+            return null;
+        }
+        try {
+            final byte[] bytes = Files.readAllBytes(protoFile.toPath());
+            final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes);
+            final Options options = new Options();
+            options.inPreferredConfig = Config.HARDWARE;
+            final Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getPath(), options);
+            if (bitmap == null) {
+                Slog.w(TAG, "Failed to load bitmap: " + bitmapFile.getPath());
+                return null;
+            }
+            final GraphicBuffer buffer = bitmap.createGraphicBufferHandle();
+            if (buffer == null) {
+                Slog.w(TAG, "Failed to retrieve gralloc buffer for bitmap: "
+                        + bitmapFile.getPath());
+                return null;
+            }
+            return new TaskSnapshot(buffer, proto.orientation,
+                    new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom));
+        } catch (IOException e) {
+            Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
+            return null;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
new file mode 100644
index 0000000..3a06c38
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -0,0 +1,335 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.TestApi;
+import android.app.ActivityManager.TaskSnapshot;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.AtomicFile;
+import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayDeque;
+
+/**
+ * Persists {@link TaskSnapshot}s to disk.
+ * <p>
+ * Test class: {@link TaskSnapshotPersisterLoaderTest}
+ */
+class TaskSnapshotPersister {
+
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM;
+    private static final String SNAPSHOTS_DIRNAME = "snapshots";
+    private static final long DELAY_MS = 100;
+    private static final String PROTO_EXTENSION = ".proto";
+    private static final String BITMAP_EXTENSION = ".png";
+
+    @GuardedBy("mLock")
+    private final ArrayDeque<WriteQueueItem> mWriteQueue = new ArrayDeque<>();
+    @GuardedBy("mLock")
+    private boolean mQueueIdling;
+    private boolean mStarted;
+    private final Object mLock = new Object();
+    private final DirectoryResolver mDirectoryResolver;
+
+    /**
+     * The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
+     * called.
+     */
+    @GuardedBy("mLock")
+    private final ArraySet<Integer> mPersistedTaskIdsSinceLastRemoveObsolete = new ArraySet<>();
+
+    TaskSnapshotPersister(DirectoryResolver resolver) {
+        mDirectoryResolver = resolver;
+    }
+
+    /**
+     * Starts persisting.
+     */
+    void start() {
+        if (!mStarted) {
+            mStarted = true;
+            mPersister.start();
+        }
+    }
+
+    /**
+     * Persists a snapshot of a task to disk.
+     *
+     * @param taskId The id of the task that needs to be persisted.
+     * @param userId The id of the user this tasks belongs to.
+     * @param snapshot The snapshot to persist.
+     */
+    void persistSnapshot(int taskId, int userId, TaskSnapshot snapshot) {
+        synchronized (mLock) {
+            mPersistedTaskIdsSinceLastRemoveObsolete.add(taskId);
+            sendToQueueLocked(new StoreWriteQueueItem(taskId, userId, snapshot));
+        }
+    }
+
+    /**
+     * Callend when a task has been removed.
+     *
+     * @param taskId The id of task that has been removed.
+     * @param userId The id of the user the task belonged to.
+     */
+    void onTaskRemovedFromRecents(int taskId, int userId) {
+        synchronized (mLock) {
+            mPersistedTaskIdsSinceLastRemoveObsolete.remove(taskId);
+            sendToQueueLocked(new DeleteWriteQueueItem(taskId, userId));
+        }
+    }
+
+    /**
+     * In case a write/delete operation was lost because the system crashed, this makes sure to
+     * clean up the directory to remove obsolete files.
+     *
+     * @param persistentTaskIds A set of task ids that exist in our in-memory model.
+     * @param runningUserIds The ids of the list of users that have tasks loaded in our in-memory
+     *                       model.
+     */
+    void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
+        synchronized (mLock) {
+            mPersistedTaskIdsSinceLastRemoveObsolete.clear();
+            sendToQueueLocked(new RemoveObsoleteFilesQueueItem(persistentTaskIds, runningUserIds));
+        }
+    }
+
+    @TestApi
+    void waitForQueueEmpty() {
+        while (true) {
+            synchronized (mLock) {
+                if (mWriteQueue.isEmpty() && mQueueIdling) {
+                    return;
+                }
+            }
+            SystemClock.sleep(100);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void sendToQueueLocked(WriteQueueItem item) {
+        mWriteQueue.offer(item);
+        mLock.notifyAll();
+    }
+
+    private File getDirectory(int userId) {
+        return new File(mDirectoryResolver.getSystemDirectoryForUser(userId), SNAPSHOTS_DIRNAME);
+    }
+
+    File getProtoFile(int taskId, int userId) {
+        return new File(getDirectory(userId), taskId + PROTO_EXTENSION);
+    }
+
+    File getBitmapFile(int taskId, int userId) {
+        return new File(getDirectory(userId), taskId + BITMAP_EXTENSION);
+    }
+
+    private boolean createDirectory(int userId) {
+        final File dir = getDirectory(userId);
+        return dir.exists() || dir.mkdirs();
+    }
+
+    private void deleteSnapshot(int taskId, int userId) {
+        final File protoFile = getProtoFile(taskId, userId);
+        final File bitmapFile = getBitmapFile(taskId, userId);
+        protoFile.delete();
+        bitmapFile.delete();
+    }
+
+    interface DirectoryResolver {
+        File getSystemDirectoryForUser(int userId);
+    }
+
+    private Thread mPersister = new Thread("TaskSnapshotPersister") {
+        public void run() {
+            android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+            while (true) {
+                WriteQueueItem next;
+                synchronized (mLock) {
+                    next = mWriteQueue.poll();
+                }
+                if (next != null) {
+                    next.write();
+                    SystemClock.sleep(DELAY_MS);
+                }
+                synchronized (mLock) {
+                    if (!mWriteQueue.isEmpty()) {
+                        continue;
+                    }
+                    try {
+                        mQueueIdling = true;
+                        mLock.wait();
+                        mQueueIdling = false;
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+        }
+    };
+
+    private abstract class WriteQueueItem {
+        abstract void write();
+    }
+
+    private class StoreWriteQueueItem extends WriteQueueItem {
+        private final int mTaskId;
+        private final int mUserId;
+        private final TaskSnapshot mSnapshot;
+
+        StoreWriteQueueItem(int taskId, int userId, TaskSnapshot snapshot) {
+            mTaskId = taskId;
+            mUserId = userId;
+            mSnapshot = snapshot;
+        }
+
+        @Override
+        void write() {
+            if (!createDirectory(mUserId)) {
+                Slog.e(TAG, "Unable to create snapshot directory for user dir="
+                        + getDirectory(mUserId));
+            }
+            boolean failed = false;
+            if (!writeProto()) {
+                failed = true;
+            }
+            if (!writeBuffer()) {
+                writeBuffer();
+                failed = true;
+            }
+            if (failed) {
+                deleteSnapshot(mTaskId, mUserId);
+            }
+        }
+
+        boolean writeProto() {
+            final TaskSnapshotProto proto = new TaskSnapshotProto();
+            proto.orientation = mSnapshot.getOrientation();
+            proto.insetLeft = mSnapshot.getContentInsets().left;
+            proto.insetTop = mSnapshot.getContentInsets().top;
+            proto.insetRight = mSnapshot.getContentInsets().right;
+            proto.insetBottom = mSnapshot.getContentInsets().bottom;
+            final byte[] bytes = TaskSnapshotProto.toByteArray(proto);
+            final File file = getProtoFile(mTaskId, mUserId);
+            final AtomicFile atomicFile = new AtomicFile(file);
+            FileOutputStream fos = null;
+            try {
+                fos = atomicFile.startWrite();
+                fos.write(bytes);
+                atomicFile.finishWrite(fos);
+            } catch (IOException e) {
+                atomicFile.failWrite(fos);
+                Slog.e(TAG, "Unable to open " + file + " for persisting. " + e);
+                return false;
+            }
+            return true;
+        }
+
+        boolean writeBuffer() {
+            final File file = getBitmapFile(mTaskId, mUserId);
+            final Bitmap bitmap = Bitmap.createHardwareBitmap(mSnapshot.getSnapshot());
+            try {
+                FileOutputStream fos = new FileOutputStream(file);
+                bitmap.compress(CompressFormat.PNG, 0 /* quality */, fos);
+                fos.close();
+            } catch (IOException e) {
+                Slog.e(TAG, "Unable to open " + file + " for persisting. " + e);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    private class DeleteWriteQueueItem extends WriteQueueItem {
+        private final int mTaskId;
+        private final int mUserId;
+
+        DeleteWriteQueueItem(int taskId, int userId) {
+            mTaskId = taskId;
+            mUserId = userId;
+        }
+
+        @Override
+        void write() {
+            deleteSnapshot(mTaskId, mUserId);
+        }
+    }
+
+    @VisibleForTesting
+    class RemoveObsoleteFilesQueueItem extends WriteQueueItem {
+        private final ArraySet<Integer> mPersistentTaskIds;
+        private final int[] mRunningUserIds;
+
+        @VisibleForTesting
+        RemoveObsoleteFilesQueueItem(ArraySet<Integer> persistentTaskIds,
+                int[] runningUserIds) {
+            mPersistentTaskIds = persistentTaskIds;
+            mRunningUserIds = runningUserIds;
+        }
+
+        @Override
+        void write() {
+            final ArraySet<Integer> newPersistedTaskIds;
+            synchronized (mLock) {
+                newPersistedTaskIds = new ArraySet<>(mPersistedTaskIdsSinceLastRemoveObsolete);
+            }
+            for (int userId : mRunningUserIds) {
+                final File dir = getDirectory(userId);
+                final String[] files = dir.list();
+                if (files == null) {
+                    continue;
+                }
+                for (String file : files) {
+                    final int taskId = getTaskId(file);
+                    if (!mPersistentTaskIds.contains(taskId)
+                            && !newPersistedTaskIds.contains(taskId)) {
+                        new File(dir, file).delete();
+                    }
+                }
+            }
+        }
+
+        @VisibleForTesting
+        int getTaskId(String fileName) {
+            if (!fileName.endsWith(PROTO_EXTENSION) && !fileName.endsWith(BITMAP_EXTENSION)) {
+                return -1;
+            }
+            final int end = fileName.lastIndexOf('.');
+            if (end == -1) {
+                return -1;
+            }
+            try {
+                return Integer.parseInt(fileName.substring(0, end));
+            } catch (NumberFormatException e) {
+                return -1;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c3e3141..4a09423 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -35,7 +35,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.Display;
 import android.view.IWindowSession;
 import android.view.Surface;
 import android.view.View;
@@ -147,6 +146,7 @@
         if (reportNextDraw) {
             reportDrawn();
         }
+        mSurface.release();
     }
 
     private void reportDrawn() {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index eeea532..53292bb 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -413,7 +413,7 @@
         switch (mStackId) {
             case PINNED_STACK_ID:
                 mTmpRect2 = mDisplayContent.getPinnedStackController().onDisplayChanged(mBounds,
-                        getDisplayInfo());
+                        mDisplayContent);
                 break;
             case DOCKED_STACK_ID:
                 repositionDockedStackAfterRotation(mTmpRect2);
@@ -684,7 +684,7 @@
         // Update the pinned stack controller after the display info is updated
         if (mStackId == PINNED_STACK_ID) {
             mDisplayContent.getPinnedStackController().onDisplayChanged(oldBounds,
-                    getDisplayInfo());
+                    mDisplayContent);
         }
 
         super.onDisplayChanged(dc);
@@ -1209,6 +1209,11 @@
     }
 
     @Override
+    public boolean isAttachedToDisplay() {
+        return mDisplayContent != null;
+    }
+
+    @Override
     public String toString() {
         return "{stackId=" + mStackId + " tasks=" + mChildren + "}";
     }
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index bbc9ed2..3c438ca 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -19,6 +19,9 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.util.EventLog;
 import android.util.Slog;
 import com.android.internal.annotations.VisibleForTesting;
@@ -37,14 +40,30 @@
  * Test class: {@link TaskWindowContainerControllerTests}
  */
 public class TaskWindowContainerController
-        extends WindowContainerController<Task, WindowContainerListener> {
+        extends WindowContainerController<Task, TaskWindowContainerListener> {
+
+    private static final int REPORT_SNAPSHOT_CHANGED = 0;
 
     private final int mTaskId;
 
-    public TaskWindowContainerController(int taskId, int stackId, int userId, Rect bounds,
-            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
-            boolean toTop, boolean showForAllUsers) {
-        super(null, WindowManagerService.getInstance());
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case REPORT_SNAPSHOT_CHANGED:
+                    if (mListener != null) {
+                        mListener.onSnapshotChanged((TaskSnapshot) msg.obj);
+                    }
+                    break;
+            }
+        }
+    };
+
+    public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
+            int stackId, int userId, Rect bounds, Configuration overrideConfig, int resizeMode,
+            boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers) {
+        super(listener, WindowManagerService.getInstance());
         mTaskId = taskId;
 
         synchronized(mWindowMap) {
@@ -117,8 +136,6 @@
                 throw new IllegalArgumentException("reparent: could not find stackId=" + stackId);
             }
             mContainer.reparent(stack, position);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.setLayoutNeeded();
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
     }
@@ -246,17 +263,8 @@
         }
     }
 
-    /**
-     * @return a graphic buffer representing a screenshot of a task
-     */
-    public TaskSnapshot getSnapshot() {
-        synchronized (mWindowMap) {
-            if (mContainer == null) {
-                Slog.w(TAG_WM, "getSnapshot: taskId " + mTaskId + " not found.");
-                return null;
-            }
-            return mService.mTaskSnapshotController.getSnapshot(mContainer);
-        }
+    void reportSnapshotChanged(TaskSnapshot snapshot) {
+        mHandler.obtainMessage(REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
new file mode 100644
index 0000000..61b202d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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.wm;
+
+import android.app.ActivityManager.TaskSnapshot;
+
+/**
+ * Interface used by the creator of the controller to listen to changes with the container.
+ */
+public interface TaskWindowContainerListener extends WindowContainerListener {
+
+    /**
+     * Called when the snapshot of this task has changed.
+     */
+    void onSnapshotChanged(TaskSnapshot snapshot);
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e231da8..5b96263 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -458,9 +458,9 @@
         return false;
     }
 
-    /** Returns the top child container or this container if there are no children. */
-    WindowContainer getTop() {
-        return mChildren.isEmpty() ? this : mChildren.peekLast();
+    /** Returns the top child container. */
+    E getTopChild() {
+        return mChildren.peekLast();
     }
 
     /** Returns true if there is still a removal being deferred */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c8c10b..c8f4bd2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -97,6 +97,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -235,6 +236,8 @@
 import java.util.HashMap;
 import java.util.List;
 
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -1113,7 +1116,8 @@
                         + displayId + ".  Aborting.");
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
-            if (!displayContent.hasAccess(session.mUid)) {
+            if (!displayContent.hasAccess(session.mUid)
+                    && !mDisplayManagerInternal.isUidPresentOnDisplay(session.mUid, displayId)) {
                 Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
                         + "does not have access: " + displayId + ".  Aborting.");
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
@@ -3859,7 +3863,7 @@
 
     @Override
     public Bitmap screenshotWallpaper() {
-        if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+        if (!checkCallingPermission(READ_FRAME_BUFFER,
                 "screenshotWallpaper()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
@@ -3880,7 +3884,7 @@
      */
     @Override
     public boolean requestAssistScreenshot(final IAssistScreenshotReceiver receiver) {
-        if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+        if (!checkCallingPermission(READ_FRAME_BUFFER,
                 "requestAssistScreenshot()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
@@ -3899,6 +3903,24 @@
         return true;
     }
 
+    public TaskSnapshot getTaskSnapshot(int taskId, int userId) {
+        return mTaskSnapshotController.getSnapshot(taskId, userId, true /* restoreFromDisk */);
+    }
+
+    /**
+     * In case a task write/delete operation was lost because the system crashed, this makes sure to
+     * clean up the directory to remove obsolete files.
+     *
+     * @param persistentTaskIds A set of task ids that exist in our in-memory model.
+     * @param runningUserIds The ids of the list of users that have tasks loaded in our in-memory
+     *                       model.
+     */
+    public void removeObsoleteTaskFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
+        synchronized (mWindowMap) {
+            mTaskSnapshotController.removeObsoleteTaskFiles(persistentTaskIds, runningUserIds);
+        }
+    }
+
     /**
      * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
      * In portrait mode, it grabs the full screenshot.
@@ -5344,6 +5366,7 @@
 
     public void systemReady() {
         mPolicy.systemReady();
+        mTaskSnapshotController.systemReady();
     }
 
     // -------------------------------------------------------------
@@ -6983,6 +7006,18 @@
         }
     }
 
+    /**
+     * Called when a task has been removed from the recent tasks list.
+     * <p>
+     * Note: This doesn't go through {@link TaskWindowContainerController} yet as the window
+     * container may not exist when this happens.
+     */
+    public void notifyTaskRemovedFromRecents(int taskId, int userId) {
+        synchronized (mWindowMap) {
+            mTaskSnapshotController.notifyTaskRemovedFromRecents(taskId, userId);
+        }
+    }
+
     @Override
     public int getDockedDividerInsetsLw() {
         return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
@@ -7148,6 +7183,7 @@
 
         mInputMonitor.dump(pw, "  ");
         mUnknownAppVisibilityController.dump(pw, "  ");
+        mTaskSnapshotController.dump(pw, "  ");
 
         if (dumpAll) {
             pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b1bf2c6..10aebe6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2304,6 +2304,9 @@
                     final WindowState win = mService.windowForClientLocked(mSession, mClient, false);
                     Slog.i(TAG, "WIN DEATH: " + win);
                     if (win != null) {
+                        if (win.mAppToken != null && win.mAppToken.findMainWindow() == win) {
+                            mService.mTaskSnapshotController.onAppDied(win.mAppToken);
+                        }
                         win.removeIfPossible(shouldKeepVisibleDeadAppWindow());
                         if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
                             // The owner of the docked divider died :( We reset the docked stack,
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 1f7bf4a0..e9c944d 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -36,7 +36,7 @@
 
 static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
     // TODO(b/31632518)
-    mHal = IConsumerIr::getService("consumerir");
+    mHal = IConsumerIr::getService();
     return mHal != nullptr;
 }
 
diff --git a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
index 17a6c297..545b3d7 100644
--- a/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
+++ b/services/core/jni/com_android_server_HardwarePropertiesManagerService.cpp
@@ -19,6 +19,7 @@
 #include "JNIHelp.h"
 #include "jni.h"
 
+#include <math.h>
 #include <stdlib.h>
 
 #include <android/hardware/thermal/1.0/IThermal.h>
@@ -56,10 +57,16 @@
     jmethodID initMethod;
 } gCpuUsageInfoClassInfo;
 
+jfloat gUndefinedTemperature;
+
 static sp<IThermal> gThermalModule;
 
 // ----------------------------------------------------------------------------
 
+float finalizeTemperature(float temperature) {
+    return isnan(temperature) ? gUndefinedTemperature : temperature;
+}
+
 static void nativeInit(JNIEnv* env, jobject obj) {
     // TODO(b/31632518)
     if (gThermalModule == nullptr) {
@@ -128,16 +135,16 @@
         if (static_cast<int>(list[i].type) == type) {
             switch (source) {
                 case TEMPERATURE_CURRENT:
-                    values[length++] = list[i].currentValue;
+                    values[length++] = finalizeTemperature(list[i].currentValue);
                     break;
                 case TEMPERATURE_THROTTLING:
-                    values[length++] = list[i].throttlingThreshold;
+                    values[length++] = finalizeTemperature(list[i].throttlingThreshold);
                     break;
                 case TEMPERATURE_SHUTDOWN:
-                    values[length++] = list[i].shutdownThreshold;
+                    values[length++] = finalizeTemperature(list[i].shutdownThreshold);
                     break;
                 case TEMPERATURE_THROTTLING_BELOW_VR_MIN:
-                    values[length++] = list[i].vrThrottlingThreshold;
+                    values[length++] = finalizeTemperature(list[i].vrThrottlingThreshold);
                     break;
             }
         }
@@ -204,6 +211,12 @@
     gCpuUsageInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gCpuUsageInfoClassInfo.initMethod = GetMethodIDOrDie(env, gCpuUsageInfoClassInfo.clazz,
                                                          "<init>", "(JJ)V");
+
+    clazz = env->FindClass("android/os/HardwarePropertiesManager");
+    jfieldID undefined_temperature_field = GetStaticFieldIDOrDie(env, clazz,
+                                                                 "UNDEFINED_TEMPERATURE", "F");
+    gUndefinedTemperature = env->GetStaticFloatField(clazz, undefined_temperature_field);
+
     return res;
 }
 
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 118562f..50bae794 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -43,7 +43,7 @@
     if (mHal != nullptr) {
         return;
     }
-    mHal = IVibrator::getService("vibrator");
+    mHal = IVibrator::getService();
 }
 
 static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 27efd05..6791da9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1462,7 +1462,11 @@
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     PointerIcon pointerIcon;
-    android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+    status_t result = android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+    if (result) {
+        jniThrowRuntimeException(env, "Failed to load custom pointer icon.");
+        return;
+    }
 
     SpriteIcon spriteIcon;
     pointerIcon.bitmap.copyTo(&spriteIcon.bitmap, kN32_SkColorType);
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 2fd0603..74af639 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -81,7 +81,7 @@
 
     // TODO(b/31632518)
     if (gLight == nullptr) {
-        gLight = ILight::getService("light");
+        gLight = ILight::getService();
     }
 
     if (gLight == nullptr) {
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index 9106441..517fce0 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 #undef LOG_NDEBUG
 #undef LOG_TAG
 #define LOG_NDEBUG 0
@@ -26,11 +25,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/endian.h>
 
 #include <chrono>
 #include <mutex>
 #include <queue>
 #include <unordered_map>
+#include <utility>
 
 #include <android-base/macros.h>
 #include <android/hardware/contexthub/1.0/IContexthub.h>
@@ -39,20 +40,20 @@
 #include "core_jni_helpers.h"
 #include "JNIHelp.h"
 
-using IContexthub = android::hardware::contexthub::V1_0::IContexthub;
+using android::hardware::contexthub::V1_0::AsyncEventType;
+using android::hardware::contexthub::V1_0::ContextHub;
+using android::hardware::contexthub::V1_0::ContextHubMsg;
+using android::hardware::contexthub::V1_0::HubAppInfo;
+using android::hardware::contexthub::V1_0::IContexthub;
+using android::hardware::contexthub::V1_0::IContexthubCallback;
+using android::hardware::contexthub::V1_0::NanoAppBinary;
+using android::hardware::contexthub::V1_0::Result;
+using android::hardware::contexthub::V1_0::TransactionResult;
 
-using Result = android::hardware::contexthub::V1_0::Result;
-using ContextHubMsg = android::hardware::contexthub::V1_0::ContextHubMsg;
-using IContexthubCallback = android::hardware::contexthub::V1_0::IContexthubCallback;
-using AsyncEventType = android::hardware::contexthub::V1_0::AsyncEventType;
-using TransactionResult = android::hardware::contexthub::V1_0::TransactionResult;
-using ContextHub = android::hardware::contexthub::V1_0::ContextHub;
-using HubAppInfo = android::hardware::contexthub::V1_0::HubAppInfo;
-
-template<typename T>
-using Return = android::hardware::Return<T>;
+using android::hardware::Return;
 
 using std::chrono::steady_clock;
+
 // If a transaction takes longer than this, we'll allow it to be
 // canceled by a new transaction.  Note we do _not_ automatically
 // cancel a transaction after this much time.  We can have a
@@ -63,6 +64,22 @@
 
 namespace android {
 
+constexpr uint32_t kNanoAppBinaryHeaderVersion = 1;
+
+// Important: this header is explicitly defined as little endian byte order, and
+// therefore may not match host endianness
+struct NanoAppBinaryHeader {
+    uint32_t headerVersion;        // 0x1 for this version
+    uint32_t magic;                // "NANO" (see NANOAPP_MAGIC in context_hub.h)
+    uint64_t appId;                // App Id, contains vendor id
+    uint32_t appVersion;           // Version of the app
+    uint32_t flags;                // Signed, encrypted
+    uint64_t hwHubType;            // Which hub type is this compiled for
+    uint8_t targetChreApiMajorVersion; // Which CHRE API version this is compiled for
+    uint8_t targetChreApiMinorVersion;
+    uint8_t reserved[6];
+} __attribute__((packed));
+
 enum HubMessageType {
     CONTEXT_HUB_APPS_ENABLE  = 1, // Enables loaded nano-app(s)
     CONTEXT_HUB_APPS_DISABLE = 2, // Disables loaded nano-app(s)
@@ -361,11 +378,12 @@
 
 ContextHubServiceDb db;
 
-int getHubIdForHubHandle(int hubHandle) {
-    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
-      return -1;
+bool getHubIdForHubHandle(int hubHandle, uint32_t *hubId) {
+    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs || hubId == nullptr) {
+        return false;
     } else {
-      return db.hubInfo.hubs[hubHandle].hubId;
+        *hubId = db.hubInfo.hubs[hubHandle].hubId;
+        return true;
     }
 }
 
@@ -380,17 +398,6 @@
     return db.appInstances[id].hubHandle;
 }
 
-int getHubIdForAppInstance(jint id) {
-    int hubHandle = getHubHandleForAppInstance(id);
-
-    if (hubHandle < 0) {
-        ALOGD("Cannot find hub instance for app instance %d", id);
-        return -1;
-    }
-
-    return db.hubInfo.hubs[hubHandle].hubId;
-}
-
 jint getAppInstanceForAppId(uint64_t app_id) {
     auto end = db.appInstances.end();
     for (auto current = db.appInstances.begin(); current != end; ++current) {
@@ -1001,6 +1008,45 @@
     return retArray;
 }
 
+Result sendLoadNanoAppRequest(uint32_t hubId,
+                              jbyte *data,
+                              size_t dataBufferLength) {
+    auto header = reinterpret_cast<const NanoAppBinaryHeader *>(data);
+    Result result;
+
+    if (dataBufferLength < sizeof(NanoAppBinaryHeader)) {
+        ALOGE("Got short NanoApp, length %zu", dataBufferLength);
+        result = Result::BAD_PARAMS;
+    } else if (header->headerVersion != htole32(kNanoAppBinaryHeaderVersion)) {
+        ALOGE("Got unexpected NanoApp header version %" PRIu32,
+              letoh32(header->headerVersion));
+        result = Result::BAD_PARAMS;
+    } else {
+        NanoAppBinary nanoapp;
+
+        // Data from the common nanoapp header goes into explicit fields
+        nanoapp.appId      = letoh64(header->appId);
+        nanoapp.appVersion = letoh32(header->appVersion);
+        nanoapp.flags      = letoh32(header->flags);
+        nanoapp.targetChreApiMajorVersion = header->targetChreApiMajorVersion;
+        nanoapp.targetChreApiMinorVersion = header->targetChreApiMinorVersion;
+
+        // Everything past the header goes in customBinary
+        auto dataBytes = reinterpret_cast<const uint8_t *>(data);
+        std::vector<uint8_t> customBinary(
+            dataBytes + sizeof(NanoAppBinaryHeader),
+            dataBytes + dataBufferLength);
+        nanoapp.customBinary = std::move(customBinary);
+
+        ALOGW("Calling Load NanoApp on hub %d", hubId);
+        result = db.hubInfo.contextHub->loadNanoApp(hubId,
+                                                    nanoapp,
+                                                    CONTEXT_HUB_LOAD_APP);
+    }
+
+    return result;
+}
+
 jint nativeSendMessage(JNIEnv *env,
                        jobject instance,
                        jintArray header_,
@@ -1012,19 +1058,18 @@
     jint retVal = -1; // Default to failure
 
     jint *header = env->GetIntArrayElements(header_, 0);
-    unsigned int numHeaderElements = env->GetArrayLength(header_);
+    size_t numHeaderElements = env->GetArrayLength(header_);
     jbyte *data = env->GetByteArrayElements(data_, 0);
-    int dataBufferLength = env->GetArrayLength(data_);
+    size_t dataBufferLength = env->GetArrayLength(data_);
 
     if (numHeaderElements < MSG_HEADER_SIZE) {
         ALOGW("Malformed header len");
         return -1;
     }
 
-    uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
+    jint appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
     uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
     int hubHandle = -1;
-    int hubId;
     uint64_t appId;
 
     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
@@ -1042,7 +1087,8 @@
         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
     }
 
-    if (hubHandle < 0) {
+    uint32_t hubId = -1;
+    if (!getHubIdForHubHandle(hubHandle, &hubId)) {
         ALOGD("Invalid hub Handle %d", hubHandle);
         return -1;
     }
@@ -1072,46 +1118,41 @@
     Result result;
 
     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
-        hubId = getHubIdForHubHandle(hubHandle);
-        ALOGW("Calling UnLoad NanoApp for app %" PRIx64 " on hub %d",
+        ALOGW("Calling UnLoad NanoApp for app %" PRIx64 " on hub %" PRIu32,
               db.appInstances[appInstanceHandle].appInfo.appId,
               hubId);
         result = db.hubInfo.contextHub->unloadNanoApp(
                 hubId, db.appInstances[appInstanceHandle].appInfo.appId, CONTEXT_HUB_UNLOAD_APP);
     } else {
-        if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
+        if (appInstanceHandle == OS_APP_ID) {
             if (msgType == CONTEXT_HUB_LOAD_APP) {
-                std::vector<uint8_t> dataVector(reinterpret_cast<uint8_t *>(data),
-                                                reinterpret_cast<uint8_t *>(data + dataBufferLength));
-                hubId = getHubIdForHubHandle(hubHandle);
-                ALOGW("Calling Load NanoApp on hub %d", hubId);
-                result = db.hubInfo.contextHub->loadNanoApp(hubId,
-                                                            dataVector,
-                                                            CONTEXT_HUB_LOAD_APP);
+                result = sendLoadNanoAppRequest(hubId, data, dataBufferLength);
             } else {
                 ALOGD("Dropping OS addresses message of type - %" PRIu32, msgType);
                 result = Result::BAD_PARAMS;
             }
         } else {
-
-            appId = getAppIdForAppInstance(header[HEADER_FIELD_APP_INSTANCE]);
-            hubId = getHubIdForAppInstance(header[HEADER_FIELD_APP_INSTANCE]);
-
-            if (appId != static_cast<uint64_t>(INVALID_APP_ID) && hubId >= 0) {
+            appId = getAppIdForAppInstance(appInstanceHandle);
+            if (appId == static_cast<uint64_t>(INVALID_APP_ID)) {
+                ALOGD("Cannot find application instance %d", appInstanceHandle);
+                result = Result::BAD_PARAMS;
+            } else if (hubHandle != getHubHandleForAppInstance(appInstanceHandle)) {
+                ALOGE("Given hubHandle (%d) doesn't match expected for app instance (%d)",
+                      hubHandle,
+                      getHubHandleForAppInstance(appInstanceHandle));
+                result = Result::BAD_PARAMS;
+            } else {
                 ContextHubMsg msg;
                 msg.appName = appId;
                 msg.msgType = msgType;
                 msg.msg.setToExternal((unsigned char *)data, dataBufferLength);
 
-                ALOGW("Sending msg of type %" PRIu32 " len %u to app %" PRIx64 " on hub %d",
+                ALOGW("Sending msg of type %" PRIu32 " len %zu to app %" PRIx64 " on hub %" PRIu32,
                        msgType,
                        dataBufferLength,
                        appId,
                        hubId);
                 result = db.hubInfo.contextHub->sendMessageToHub(hubId, msg);
-            } else {
-                ALOGD("Cannot find application instance %u", header[HEADER_FIELD_APP_INSTANCE]);
-                result = Result::BAD_PARAMS;
             }
         }
     }
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 5a20bed..01a1efc 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -673,7 +673,7 @@
     }
 
     if (flags & static_cast<uint32_t>(GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL)) {
-        SET(AgcLevelDb, measurement->agcLevelDb);
+        SET(AutomaticGainControlLevelInDb, measurement->agcLevelDb);
     }
 
     return object.get();
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 179fba0..9f528b1 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -327,7 +327,7 @@
 
 JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
     // TODO(b/31632518)
-    sp<ITvInput> tvInput = ITvInput::getService("tv.input");
+    sp<ITvInput> tvInput = ITvInput::getService();
     if (tvInput == nullptr) {
         ALOGE("Couldn't get tv.input service.");
         return nullptr;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 040188d..f3b0131 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -69,6 +69,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.NetworkEvent;
 import android.app.admin.PasswordMetrics;
+import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SecurityLog;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.app.admin.SystemUpdatePolicy;
@@ -191,6 +192,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -235,7 +237,7 @@
 
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
-    private static final long MS_PER_DAY = 86400 * 1000;
+    private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
 
     private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
 
@@ -330,7 +332,7 @@
      * Minimum timeout in milliseconds after which unlocking with weak auth times out,
      * i.e. the user has to use a strong authentication method like password, PIN or pattern.
      */
-    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
+    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1);
 
     /**
      * Strings logged with {@link
@@ -1154,7 +1156,7 @@
                 } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) {
                     keepUninstalledPackages = readPackageList(parser, tag);
                 } else if (TAG_USER_RESTRICTIONS.equals(tag)) {
-                    UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+                    userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
                     readAttributeValues(
                             parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet);
@@ -2663,14 +2665,14 @@
             // Ignore
         }
 
+        // Generate a list of admins from the admin map
+        policy.mAdminList.addAll(policy.mAdminMap.values());
+
         // Might need to upgrade the file by rewriting it
         if (needsRewrite) {
             saveSettingsLocked(userHandle);
         }
 
-        // Generate a list of admins from the admin map
-        policy.mAdminList.addAll(policy.mAdminMap.values());
-
         validatePasswordOwnerLocked(policy);
         updateMaximumTimeToLockLocked(userHandle);
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
@@ -4526,9 +4528,13 @@
                 mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
             }
         } else {
-            synchronized (this) {
-                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            }
+            enforceProfileOrDeviceOwner(who);
+        }
+    }
+
+    private void enforceProfileOrDeviceOwner(ComponentName who) {
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         }
     }
 
@@ -4538,9 +4544,7 @@
                 throw new SecurityException("who == null, but caller is not cert installer");
             }
         } else {
-            synchronized (this) {
-                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            }
+            enforceProfileOrDeviceOwner(who);
         }
     }
 
@@ -4830,9 +4834,7 @@
     @Override
     public boolean setAlwaysOnVpnPackage(ComponentName admin, String vpnPackage, boolean lockdown)
             throws SecurityException {
-        synchronized (this) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-        }
+        enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
         final long token = mInjector.binderClearCallingIdentity();
@@ -4854,9 +4856,7 @@
     @Override
     public String getAlwaysOnVpnPackage(ComponentName admin)
             throws SecurityException {
-        synchronized (this) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-        }
+        enforceProfileOrDeviceOwner(admin);
 
         final int userId = mInjector.userHandleGetCallingUserId();
         final long token = mInjector.binderClearCallingIdentity();
@@ -5574,7 +5574,7 @@
     }
 
     /**
-     * Set whether auto time is required by the specified admin (must be device owner).
+     * Set whether auto time is required by the specified admin (must be device or profile owner).
      */
     @Override
     public void setAutoTimeRequired(ComponentName who, boolean required) {
@@ -5585,7 +5585,7 @@
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (admin.requireAutoTime != required) {
                 admin.requireAutoTime = required;
                 saveSettingsLocked(userHandle);
@@ -5604,7 +5604,7 @@
     }
 
     /**
-     * Returns whether or not auto time is required by the device owner.
+     * Returns whether or not auto time is required by the device owner or any profile owner.
      */
     @Override
     public boolean getAutoTimeRequired() {
@@ -5613,7 +5613,20 @@
         }
         synchronized (this) {
             ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
-            return (deviceOwner != null) ? deviceOwner.requireAutoTime : false;
+            if (deviceOwner != null && deviceOwner.requireAutoTime) {
+                // If the device owner enforces auto time, we don't need to check the PO's
+                return true;
+            }
+
+            // Now check to see if any profile owner on any user enforces auto time
+            for (Integer userId : mOwners.getProfileOwnerKeys()) {
+                ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+                if (profileOwner != null && profileOwner.requireAutoTime) {
+                    return true;
+                }
+            }
+
+            return false;
         }
     }
 
@@ -6783,6 +6796,18 @@
         enforceManageUsers();
     }
 
+    private void enforceProfileOwnerOrSystemUser(ComponentName admin) {
+        synchronized (this) {
+            if (getActiveAdminWithPolicyForUidLocked(admin,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid())
+                            != null) {
+                return;
+            }
+        }
+        Preconditions.checkState(isCallerWithSystemUid(),
+                "Only profile owner, device owner and system may call this method.");
+    }
+
     private void ensureCallerPackage(@Nullable String packageName) {
         if (packageName == null) {
             Preconditions.checkState(isCallerWithSystemUid(),
@@ -6999,9 +7024,7 @@
 
     private void enforceCanManageApplicationRestrictions(ComponentName who) {
         if (who != null) {
-            synchronized (this) {
-                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            }
+            enforceProfileOrDeviceOwner(who);
         } else if (!isCallerApplicationRestrictionsManagingPackage()) {
             throw new SecurityException(
                     "No admin component given, and caller cannot manage application restrictions "
@@ -7767,7 +7790,7 @@
 
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            ActiveAdmin activeAdmin =
+            final ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who,
                             DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             final boolean isDeviceOwner = isDeviceOwner(who, userHandle);
@@ -7782,7 +7805,12 @@
             }
 
             // Save the restriction to ActiveAdmin.
-            activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner);
+            final Bundle restrictions = activeAdmin.ensureUserRestrictions();
+            if (enabledFromThisOwner) {
+                restrictions.putBoolean(key, true);
+            } else {
+                restrictions.remove(key);
+            }
             saveUserRestrictionsLocked(userHandle);
         }
     }
@@ -7795,39 +7823,46 @@
 
     private void pushUserRestrictions(int userId) {
         synchronized (this) {
-            final Bundle global;
-            final Bundle local = new Bundle();
-            if (mOwners.isDeviceOwnerUserId(userId)) {
-                global = new Bundle();
+            final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
+            final Bundle userRestrictions;
+            // Whether device owner enforces camera restriction.
+            boolean disallowCameraGlobally = false;
 
+            if (isDeviceOwner) {
                 final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
                 if (deviceOwner == null) {
                     return; // Shouldn't happen.
                 }
-
-                UserRestrictionsUtils.sortToGlobalAndLocal(deviceOwner.userRestrictions,
-                        global, local);
+                userRestrictions = deviceOwner.userRestrictions;
                 // DO can disable camera globally.
-                if (deviceOwner.disableCamera) {
-                    global.putBoolean(UserManager.DISALLOW_CAMERA, true);
-                }
+                disallowCameraGlobally = deviceOwner.disableCamera;
             } else {
-                global = null;
+                final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+                userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null;
+            }
 
-                ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
-                if (profileOwner != null) {
-                    UserRestrictionsUtils.merge(local, profileOwner.userRestrictions);
-                }
-            }
-            // Also merge in *local* camera restriction.
-            if (getCameraDisabled(/* who= */ null,
-                    userId, /* mergeDeviceOwnerRestriction= */ false)) {
-                local.putBoolean(UserManager.DISALLOW_CAMERA, true);
-            }
-            mUserManagerInternal.setDevicePolicyUserRestrictions(userId, local, global);
+            // Whether any admin enforces camera restriction.
+            final int cameraRestrictionScope =
+                    getCameraRestrictionScopeLocked(userId, disallowCameraGlobally);
+
+            mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions,
+                    isDeviceOwner, cameraRestrictionScope);
         }
     }
 
+    /**
+     * Get the scope of camera restriction for a given user if any.
+     */
+    private int getCameraRestrictionScopeLocked(int userId, boolean disallowCameraGlobally) {
+        if (disallowCameraGlobally) {
+            return UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+        } else if (getCameraDisabled(
+                /* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) {
+            return UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+        }
+        return UserManagerInternal.CAMERA_NOT_DISABLED;
+    }
+
     @Override
     public Bundle getUserRestrictions(ComponentName who) {
         if (!mHasFeature) {
@@ -8792,7 +8827,7 @@
     }
 
     @Override
-    public void notifyPendingSystemUpdate(long updateReceivedTime) {
+    public void notifyPendingSystemUpdate(@Nullable SystemUpdateInfo info) {
         mContext.enforceCallingOrSelfPermission(permission.NOTIFY_PENDING_SYSTEM_UPDATE,
                 "Only the system update service can broadcast update information");
 
@@ -8801,9 +8836,15 @@
                     "can broadcast update information.");
             return;
         }
-        final Intent intent = new Intent(DeviceAdminReceiver.ACTION_NOTIFY_PENDING_SYSTEM_UPDATE);
-        intent.putExtra(DeviceAdminReceiver.EXTRA_SYSTEM_UPDATE_RECEIVED_TIME,
-                updateReceivedTime);
+
+        if (!mOwners.saveSystemUpdateInfo(info)) {
+            // Pending system update hasn't changed, don't send duplicate notification.
+            return;
+        }
+
+        final Intent intent = new Intent(DeviceAdminReceiver.ACTION_NOTIFY_PENDING_SYSTEM_UPDATE)
+                .putExtra(DeviceAdminReceiver.EXTRA_SYSTEM_UPDATE_RECEIVED_TIME,
+                        info == null ? -1 : info.getReceivedTime());
 
         final long ident = mInjector.binderClearCallingIdentity();
         try {
@@ -8842,6 +8883,14 @@
     }
 
     @Override
+    public SystemUpdateInfo getPendingSystemUpdate(ComponentName admin) {
+        Preconditions.checkNotNull(admin, "ComponentName is null");
+        enforceProfileOrDeviceOwner(admin);
+
+        return mOwners.getSystemUpdateInfo();
+    }
+
+    @Override
     public void setPermissionPolicy(ComponentName admin, int policy) throws RemoteException {
         int userId = UserHandle.getCallingUserId();
         synchronized (this) {
@@ -8913,8 +8962,8 @@
         PackageManager packageManager = mInjector.getPackageManager();
 
         UserHandle user = mInjector.binderGetCallingUserHandle();
+        enforceProfileOwnerOrSystemUser(admin);
         synchronized (this) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             long ident = mInjector.binderClearCallingIdentity();
             try {
                 int granted = mIPackageManager.checkPermission(permission,
@@ -9168,9 +9217,7 @@
 
     @Override
     public boolean isManagedProfile(ComponentName admin) {
-        synchronized (this) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-        }
+        enforceProfileOrDeviceOwner(admin);
         return isManagedProfile(mInjector.userHandleGetCallingUserId());
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index b53933e..a5500dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -17,6 +17,7 @@
 package com.android.server.devicepolicy;
 
 import android.annotation.Nullable;
+import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.content.ComponentName;
 import android.content.pm.PackageManagerInternal;
@@ -47,13 +48,14 @@
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 import libcore.io.IoUtils;
 
 /**
- * Stores and restores state for the Device and Profile owners. By definition there can be
- * only one device owner, but there may be a profile owner for each user.
+ * Stores and restores state for the Device and Profile owners and related device-wide information.
+ * By definition there can be only one device owner, but there may be a profile owner for each user.
  *
  * <p>This class is thread safe, so individual methods can safely be called without locking.
  * However, caller must still synchronize on their side to ensure integrity between multiple calls.
@@ -65,6 +67,7 @@
 
     private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml";
 
+    // XML storing device owner info, system update policy and pending OTA update information.
     private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
 
     private static final String PROFILE_OWNER_XML = "profile_owner.xml";
@@ -73,6 +76,8 @@
 
     private static final String TAG_DEVICE_OWNER = "device-owner";
     private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
+    private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
+    private static final String TAG_PENDING_OTA_INFO = "pending-ota-info";
     private static final String TAG_PROFILE_OWNER = "profile-owner";
     // Holds "context" for device-owner, this must not be show up before device-owner.
     private static final String TAG_DEVICE_OWNER_CONTEXT = "device-owner-context";
@@ -85,8 +90,6 @@
     private static final String ATTR_USERID = "userId";
     private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
 
-    private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
-
     private final UserManager mUserManager;
     private final UserManagerInternal mUserManagerInternal;
     private final PackageManagerInternal mPackageManagerInternal;
@@ -102,6 +105,10 @@
     // Local system update policy controllable by device owner.
     private SystemUpdatePolicy mSystemUpdatePolicy;
 
+    // Pending OTA info if there is one.
+    @Nullable
+    private SystemUpdateInfo mSystemUpdateInfo;
+
     private final Object mLock = new Object();
 
     public Owners(UserManager userManager,
@@ -468,6 +475,32 @@
         }
     }
 
+    /**
+     * Saves the given {@link SystemUpdateInfo} if it is different from the existing one, or if
+     * none exists.
+     *
+     * @return Whether the saved system update information has changed.
+     */
+    boolean saveSystemUpdateInfo(@Nullable SystemUpdateInfo newInfo) {
+        synchronized (mLock) {
+            // Check if we already have the same update information.
+            if (Objects.equals(newInfo, mSystemUpdateInfo)) {
+                return false;
+            }
+
+            mSystemUpdateInfo = newInfo;
+            new DeviceOwnerReadWriter().writeToFileLocked();
+            return true;
+        }
+    }
+
+    @Nullable
+    public SystemUpdateInfo getSystemUpdateInfo() {
+        synchronized (mLock) {
+            return mSystemUpdateInfo;
+        }
+    }
+
     private abstract static class FileReadWriter {
         private final File mFile;
 
@@ -573,7 +606,7 @@
                     }
                 }
             } catch (XmlPullParserException | IOException e) {
-                Slog.e(TAG, "Error parsing device-owner file", e);
+                Slog.e(TAG, "Error parsing owners information file", e);
             } finally {
                 IoUtils.closeQuietly(input);
             }
@@ -592,7 +625,8 @@
 
         @Override
         boolean shouldWrite() {
-            return (mDeviceOwner != null) || (mSystemUpdatePolicy != null);
+            return (mDeviceOwner != null) || (mSystemUpdatePolicy != null)
+                    || (mSystemUpdateInfo != null);
         }
 
         @Override
@@ -609,6 +643,10 @@
                 mSystemUpdatePolicy.saveToXml(out);
                 out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
             }
+
+            if (mSystemUpdateInfo != null) {
+                mSystemUpdateInfo.writeToXml(out, TAG_PENDING_OTA_INFO);
+            }
         }
 
         @Override
@@ -637,6 +675,9 @@
                 case TAG_SYSTEM_UPDATE_POLICY:
                     mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
                     break;
+                case TAG_PENDING_OTA_INFO:
+                    mSystemUpdateInfo = SystemUpdateInfo.readFromXml(parser);
+                    break;
                 default:
                     Slog.e(TAG, "Unexpected tag: " + tag);
                     return false;
@@ -783,7 +824,6 @@
         }
         if (mSystemUpdatePolicy != null) {
             if (needBlank) {
-                needBlank = false;
                 pw.println();
             }
             pw.println(prefix + "System Update Policy: " + mSystemUpdatePolicy);
@@ -792,7 +832,6 @@
         if (mProfileOwners != null) {
             for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
                 if (needBlank) {
-                    needBlank = false;
                     pw.println();
                 }
                 pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
@@ -800,6 +839,13 @@
                 needBlank = true;
             }
         }
+        if (mSystemUpdateInfo != null) {
+            if (needBlank) {
+                pw.println();
+            }
+            pw.println(prefix + "Pending System Update: " + mSystemUpdateInfo);
+            needBlank = true;
+        }
     }
 
     File getLegacyConfigFileWithTestOverride() {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 08fb591..c3ef23b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -280,14 +280,8 @@
             Slog.i(TAG, "Entered the Android system server!");
             int uptimeMillis = (int) SystemClock.elapsedRealtime();
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
-            if (!mRuntimeRestart && !mFirstBoot) {
+            if (!mRuntimeRestart) {
                 MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
-                // Also report when first stage of init has started
-                long initStartNs = SystemProperties.getLong("ro.boottime.init", -1);
-                if (initStartNs >= 0) {
-                    MetricsLogger.histogram(null, "boot_android_init",
-                            (int)(initStartNs / 1000000));
-                }
             }
 
             // In case the runtime switched since last boot (such as when
@@ -355,7 +349,6 @@
             // Create the system service manager.
             mSystemServiceManager = new SystemServiceManager(mSystemContext);
             mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
-            mSystemServiceManager.setFirstBoot(mFirstBoot);
             LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
             // Prepare the thread pool for init tasks that can be parallelized
             SystemServerInitThreadPool.get();
@@ -382,9 +375,14 @@
         if (StrictMode.conditionallyEnableDebugLogging()) {
             Slog.i(TAG, "Enabled StrictMode for system server main thread.");
         }
-        if (!mRuntimeRestart && !mFirstBoot) {
-            MetricsLogger.histogram(null, "boot_system_server_ready",
-                    (int) SystemClock.elapsedRealtime());
+        if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
+            int uptimeMillis = (int) SystemClock.elapsedRealtime();
+            MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
+            final int MAX_UPTIME_MILLIS = 60 * 1000;
+            if (uptimeMillis > MAX_UPTIME_MILLIS) {
+                Slog.wtf("SystemServerTiming",
+                        "SystemServer init took too long. uptimeMillis=" + uptimeMillis);
+            }
         }
 
         // Loop forever.
@@ -392,6 +390,10 @@
         throw new RuntimeException("Main thread loop unexpectedly exited");
     }
 
+    private boolean isFirstBootOrUpgrade() {
+        return mPackageManagerService.isFirstBoot() || mPackageManagerService.isUpgrade();
+    }
+
     private void reportWtf(String msg, Throwable e) {
         Slog.w(TAG, "***********************************************");
         Slog.wtf(TAG, "BOOT FAILURE " + msg, e);
@@ -487,6 +489,18 @@
         mActivityManagerService.initPowerManagement();
         traceEnd();
 
+        // Bring up recovery system in case a rescue party needs a reboot
+        if (!SystemProperties.getBoolean("config.disable_noncore", false)) {
+            traceBeginAndSlog("StartRecoverySystemService");
+            mSystemServiceManager.startService(RecoverySystemService.class);
+            traceEnd();
+        }
+
+        // Now that we have the bare essentials of the OS up and running, take
+        // note that we just booted, which might send out a rescue party if
+        // we're stuck in a runtime restart loop.
+        RescueParty.noteBoot(mSystemContext);
+
         // Manages LEDs and display backlight so we need it to bring up the display.
         traceBeginAndSlog("StartLightsService");
         mSystemServiceManager.startService(LightsService.class);
@@ -524,7 +538,7 @@
         mFirstBoot = mPackageManagerService.isFirstBoot();
         mPackageManager = mSystemContext.getPackageManager();
         traceEnd();
-        if (!mRuntimeRestart && !mFirstBoot) {
+        if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
             MetricsLogger.histogram(null, "boot_package_manager_init_ready",
                     (int) SystemClock.elapsedRealtime());
         }
@@ -644,6 +658,11 @@
 
         boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
+        // For debugging RescueParty
+        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_system", false)) {
+            throw new RuntimeException();
+        }
+
         try {
             Slog.i(TAG, "Reading configuration...");
             traceBeginAndSlog("ReadingSystemConfig");
@@ -920,6 +939,12 @@
                 traceEnd();
             }
 
+            if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartFontServiceManager");
+                mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
+                traceEnd();
+            }
+
             if (!disableNonCoreServices && !disableTextServices) {
                 traceBeginAndSlog("StartTextServicesManager");
                 mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
@@ -955,6 +980,21 @@
                 }
                 traceEnd();
 
+                // Wifi Service must be started first for wifi-related services.
+                traceBeginAndSlog("StartWifi");
+                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+                traceEnd();
+                traceBeginAndSlog("StartWifiScanning");
+                mSystemServiceManager.startService(
+                        "com.android.server.wifi.scanner.WifiScanningService");
+                traceEnd();
+
+                if (!disableRtt) {
+                    traceBeginAndSlog("StartWifiRtt");
+                    mSystemServiceManager.startService("com.android.server.wifi.RttService");
+                    traceEnd();
+                }
+
                 if (context.getPackageManager().hasSystemFeature(
                         PackageManager.FEATURE_WIFI_AWARE)) {
                     traceBeginAndSlog("StartWifiAware");
@@ -970,19 +1010,6 @@
                     mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
                     traceEnd();
                 }
-                traceBeginAndSlog("StartWifi");
-                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
-                traceEnd();
-                traceBeginAndSlog("StartWifiScanning");
-                mSystemServiceManager.startService(
-                            "com.android.server.wifi.scanner.WifiScanningService");
-                traceEnd();
-
-                if (!disableRtt) {
-                    traceBeginAndSlog("StartWifiRtt");
-                    mSystemServiceManager.startService("com.android.server.wifi.RttService");
-                    traceEnd();
-                }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
@@ -1025,12 +1052,6 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartRecoverSystemService");
-                mSystemServiceManager.startService(RecoverySystemService.class);
-                traceEnd();
-            }
-
             /*
              * StorageManagerService has a few dependencies: Notification Manager and
              * AppWidget Provider. Make sure StorageManagerService is completely started
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 8dd05b1..2624f0b 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -30,6 +30,7 @@
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
+import android.net.TrafficStats;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.DhcpClientEvent;
 import android.net.metrics.DhcpErrorEvent;
@@ -303,6 +304,7 @@
     }
 
     private boolean initUdpSocket() {
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP);
         try {
             mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
@@ -314,6 +316,8 @@
         } catch(SocketException|ErrnoException e) {
             Log.e(TAG, "Error creating UDP socket", e);
             return false;
+        } finally {
+            TrafficStats.setThreadStatsTag(oldTag);
         }
         return true;
     }
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 87018ec..abdf683 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -865,13 +865,7 @@
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
             newLp.addRoute(route);
         }
-        for (InetAddress dns : netlinkLinkProperties.getDnsServers()) {
-            // Only add likely reachable DNS servers.
-            // TODO: investigate deleting this.
-            if (newLp.isReachable(dns)) {
-                newLp.addDnsServer(dns);
-            }
-        }
+        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
 
         // [3] Add in data from DHCPv4, if available.
         //
@@ -881,13 +875,7 @@
             for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
                 newLp.addRoute(route);
             }
-            for (InetAddress dns : mDhcpResults.dnsServers) {
-                // Only add likely reachable DNS servers.
-                // TODO: investigate deleting this.
-                if (newLp.isReachable(dns)) {
-                    newLp.addDnsServer(dns);
-                }
-            }
+            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
             newLp.setDomains(mDhcpResults.domains);
 
             if (mDhcpResults.mtu != 0) {
@@ -909,6 +897,18 @@
         return newLp;
     }
 
+    private static void addAllReachableDnsServers(
+            LinkProperties lp, Iterable<InetAddress> dnses) {
+        // TODO: Investigate deleting this reachability check.  We should be
+        // able to pass everything down to netd and let netd do evaluation
+        // and RFC6724-style sorting.
+        for (InetAddress dns : dnses) {
+            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
+                lp.addDnsServer(dns);
+            }
+        }
+    }
+
     // Returns false if we have lost provisioning, true otherwise.
     private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
         final LinkProperties newLp = assembleLinkProperties();
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 6802cff..ba1621d 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -22,6 +22,7 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
+import android.net.TrafficStats;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructGroupReq;
@@ -563,6 +564,7 @@
     private boolean createSocket() {
         final int SEND_TIMEOUT_MS = 300;
 
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NEIGHBOR);
         try {
             mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
             // Setting SNDTIMEO is purely for defensive purposes.
@@ -574,6 +576,8 @@
         } catch (ErrnoException | IOException e) {
             Log.e(TAG, "Failed to create RA daemon socket: " + e);
             return false;
+        } finally {
+            TrafficStats.setThreadStatsTag(oldTag);
         }
 
         return true;
diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/notification/AndroidManifest.xml
index 1ed8ed0..92f155f 100644
--- a/services/tests/notification/AndroidManifest.xml
+++ b/services/tests/notification/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 40938fd..9b74fcc 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,7 +24,9 @@
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
 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;
@@ -33,18 +35,25 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.MessageQueue;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -58,30 +67,76 @@
 @RunWith(AndroidJUnit4.class)
 public class NotificationManagerServiceTest {
     private final String pkg = "com.android.server.notification";
-    private final int uid = 0;
+    private final int uid = Binder.getCallingUid();
     private NotificationManagerService mNotificationManagerService;
     private INotificationManager mBinderService;
     private IPackageManager mPackageManager = mock(IPackageManager.class);
+    private Context mContext;
+    private HandlerThread mThread;
 
     @Before
     @UiThreadTest
     public void setUp() throws Exception {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        mNotificationManagerService = new NotificationManagerService(context);
+        mContext = InstrumentationRegistry.getTargetContext();
+        mNotificationManagerService = new NotificationManagerService(mContext);
 
         // MockPackageManager - default returns ApplicationInfo with matching calling UID
         final ApplicationInfo applicationInfo = new ApplicationInfo();
-        applicationInfo.uid = Binder.getCallingUid();
+        applicationInfo.uid = uid;
         when(mPackageManager.getApplicationInfo(any(), anyInt(), anyInt()))
                 .thenReturn(applicationInfo);
+        final PackageManager mockPackageManagerClient = mock(PackageManager.class);
+        when(mockPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(applicationInfo);
         final LightsManager mockLightsManager = mock(LightsManager.class);
         when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
-        mNotificationManagerService.init(mPackageManager, mockLightsManager);
+        // Use a separate thread for service looper.
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        // Mock NotificationListeners to bypass security checks.
+        final NotificationManagerService.NotificationListeners mockNotificationListeners =
+                mock(NotificationManagerService.NotificationListeners.class);
+        when(mockNotificationListeners.checkServiceTokenLocked(any())).thenReturn(
+                mockNotificationListeners.new ManagedServiceInfo(null,
+                        new ComponentName(pkg, "test_class"), uid, true, null, 0));
+
+        mNotificationManagerService.init(mThread.getLooper(), mPackageManager,
+                mockPackageManagerClient, mockLightsManager, mockNotificationListeners);
 
         // Tests call directly into the Binder.
         mBinderService = mNotificationManagerService.getBinderService();
     }
 
+    public void waitForIdle() throws Exception {
+        MessageQueue queue = mThread.getLooper().getQueue();
+        CountDownLatch latch = new CountDownLatch(1);
+        queue.addIdleHandler(new MessageQueue.IdleHandler() {
+                @Override public boolean queueIdle() {
+                    latch.countDown();
+                    return false;
+                }
+        });
+        latch.await();
+        if (!queue.isIdle()) {
+            waitForIdle();
+        }
+    }
+
+    private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
+        if (channel == null) {
+            channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+        }
+        Notification n = new Notification.Builder(mContext)
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .build();
+        StatusBarNotification sbn = new StatusBarNotification(mContext.getPackageName(),
+                mContext.getPackageName(), channel, 1, "tag", uid, 0,
+                n, new UserHandle(uid), null, 0);
+        return new NotificationRecord(mContext, sbn);
+    }
+
     @Test
     @UiThreadTest
     public void testCreateNotificationChannels_SingleChannel() throws Exception {
@@ -203,15 +258,120 @@
         verify(usageStats, times(1)).registerBlocked(eq(r));
     }
 
-    private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
-        final Context context = InstrumentationRegistry.getTargetContext();
-        Notification n = new Notification.Builder(context)
-                .setContentTitle("foo")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setPriority(Notification.PRIORITY_HIGH)
-                .build();
-        StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, channel, 1, "tag", uid, uid,
-                n, UserHandle.SYSTEM, null, uid);
-        return new NotificationRecord(context, sbn);
+    @Test
+    @UiThreadTest
+    public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
+        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
+                generateNotificationRecord(null).getNotification(), new int[1], 0);
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(mContext.getPackageName());
+        assertEquals(1, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
+        mBinderService.enqueueNotificationWithTag(mContext.getPackageName(), "opPkg", "tag", 0,
+                generateNotificationRecord(null).getNotification(), new int[1], 0);
+        mBinderService.cancelNotificationWithTag(mContext.getPackageName(), "tag", 0, 0);
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(mContext.getPackageName());
+        assertEquals(0, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mBinderService.cancelNotificationsFromListener(null, null);
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(0, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mBinderService.cancelAllNotifications(sbn.getPackageName(), sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(0, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mBinderService.cancelAllNotifications(sbn.getPackageName(), sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(1, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(1, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mBinderService.cancelAllNotifications(null, sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(0, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], UserHandle.USER_ALL);
+        // Null pkg is how we signal a user switch.
+        mBinderService.cancelAllNotifications(null, sbn.getUserId());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(1, notifs.length);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testSnoozeNotificationImmediatelyAfterEnqueue() throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
+        mBinderService.snoozeNotificationFromListener(null, sbn.getKey());
+        waitForIdle();
+        StatusBarNotification[] notifs =
+                mBinderService.getActiveNotifications(sbn.getPackageName());
+        assertEquals(0, notifs.length);
     }
 }
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 f8061f6..59ac427 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,7 @@
  */
 package com.android.server.notification;
 
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.fail;
 
 import org.junit.Before;
@@ -34,6 +35,7 @@
 import android.app.NotificationManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
 import android.net.Uri;
 import android.os.Build;
 import android.os.UserHandle;
@@ -49,6 +51,9 @@
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -166,7 +171,7 @@
         serializer.flush();
 
         for (String channelId : channelIds) {
-            mHelper.deleteNotificationChannel(pkg, uid, channelId);
+            mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
         }
         return baos;
     }
@@ -246,26 +251,23 @@
         channel2.enableVibration(true);
         channel2.setVibrationPattern(new long[] {100, 67, 145, 156});
 
-        mHelper.createNotificationChannel(pkg, uid, channel1, false);
+        mHelper.createNotificationChannel(pkg, uid, channel1, true);
         mHelper.createNotificationChannel(pkg, uid, channel2, false);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(), channel2.getId(),
                 NotificationChannel.DEFAULT_CHANNEL_ID);
 
-        mHelper.deleteNotificationChannel(pkg, uid, channel1.getId());
-        mHelper.deleteNotificationChannel(pkg, uid, channel2.getId());
-        mHelper.deleteNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
-
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
                 null);
         parser.nextTag();
         mHelper.readXml(parser, false);
 
-        assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId()));
-        compareChannels(channel2, mHelper.getNotificationChannel(pkg, uid, channel2.getId()));
-        assertNotNull(
-                mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID));
+        assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId(), false));
+        compareChannels(channel2,
+                mHelper.getNotificationChannel(pkg, uid, channel2.getId(), false));
+        assertNotNull(mHelper.getNotificationChannel(
+                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false));
     }
 
     @Test
@@ -284,8 +286,8 @@
         parser.nextTag();
         mHelper.readXml(parser, false);
 
-        final NotificationChannel updated =
-                mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
+        final NotificationChannel updated = mHelper.getNotificationChannel(
+                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
         assertFalse(updated.canBypassDnd());
         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,updated.getLockscreenVisibility());
@@ -298,8 +300,8 @@
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN);
         mHelper.createNotificationChannel(pkg, uid, channel1, true);
 
-        final NotificationChannel defaultChannel =
-                mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
+        final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
+                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         mHelper.updateNotificationChannel(pkg, uid, defaultChannel);
 
@@ -313,7 +315,7 @@
         mHelper.readXml(parser, false);
 
         assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
-                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID).getImportance());
+                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
     }
 
     @Test
@@ -331,8 +333,8 @@
         parser.nextTag();
         mHelper.readXml(parser, false);
 
-        final NotificationChannel updated1 =
-            mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID);
+        final NotificationChannel updated1 = mHelper.getNotificationChannel(
+                pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
         assertTrue(updated1.canBypassDnd());
         assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
@@ -340,8 +342,8 @@
             | NotificationChannel.USER_LOCKED_PRIORITY
             | NotificationChannel.USER_LOCKED_VISIBILITY, updated1.getUserLockedFields());
 
-        final NotificationChannel updated2 =
-            mHelper.getNotificationChannel(pkg2, uid2, NotificationChannel.DEFAULT_CHANNEL_ID);
+        final NotificationChannel updated2 = mHelper.getNotificationChannel(
+                pkg2, uid2, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         // clamped
         assertEquals(NotificationManager.IMPORTANCE_LOW, updated2.getImportance());
         assertFalse(updated2.canBypassDnd());
@@ -378,7 +380,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -399,7 +401,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -421,7 +423,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -442,7 +444,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -463,7 +465,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -484,7 +486,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -503,7 +505,7 @@
         mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
 
         // no fields should be changed
-        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
@@ -529,13 +531,13 @@
         mHelper.updateNotificationChannel(pkg, uid, channel2);
 
         // all fields should be changed
-        assertEquals(channel2, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
+        assertEquals(channel2, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false));
     }
 
     @Test
     public void testGetChannelWithFallback() throws Exception {
         NotificationChannel channel =
-                mHelper.getNotificationChannelWithFallback(pkg, uid, "garbage");
+                mHelper.getNotificationChannelWithFallback(pkg, uid, "garbage", false);
         assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID, channel.getId());
     }
 
@@ -557,7 +559,7 @@
         mHelper.createNotificationChannel(pkg, uid, channel, true);
 
         NotificationChannel savedChannel =
-                mHelper.getNotificationChannel(pkg, uid, channel.getId());
+                mHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
 
         assertEquals(channel.getName(), savedChannel.getName());
         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
@@ -584,7 +586,7 @@
         mHelper.createNotificationChannel(pkg, uid, channel, true);
 
         NotificationChannel savedChannel =
-                mHelper.getNotificationChannel(pkg, uid, channel.getId());
+                mHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
 
         assertEquals(channel.getName(), savedChannel.getName());
         assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
@@ -592,4 +594,168 @@
         assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
         assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
     }
+
+    @Test
+    public void testGetDeletedChannel() throws Exception {
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+        channel.setSound(new Uri.Builder().scheme("test").build());
+        channel.setLights(true);
+        channel.setBypassDnd(true);
+        channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+        channel.enableVibration(true);
+        channel.setVibrationPattern(new long[] {100, 67, 145, 156});
+
+        mHelper.createNotificationChannel(pkg, uid, channel, true);
+        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
+
+        // Does not return deleted channel
+        NotificationChannel response =
+                mHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
+        assertNull(response);
+
+        // Returns deleted channel
+        response = mHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
+        compareChannels(channel, response);
+        assertTrue(response.isDeleted());
+    }
+
+    @Test
+    public void testGetDeletedChannels() throws Exception {
+        Map<String, NotificationChannel> channelMap = new HashMap<>();
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+        channel.setSound(new Uri.Builder().scheme("test").build());
+        channel.setLights(true);
+        channel.setBypassDnd(true);
+        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
+        channel.enableVibration(true);
+        channel.setVibrationPattern(new long[] {100, 67, 145, 156});
+        channelMap.put(channel.getId(), channel);
+        NotificationChannel channel2 =
+                new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
+        channelMap.put(channel2.getId(), channel2);
+        mHelper.createNotificationChannel(pkg, uid, channel, true);
+        mHelper.createNotificationChannel(pkg, uid, channel2, true);
+
+        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
+
+        // Returns only non-deleted channels
+        List<NotificationChannel> channels =
+                mHelper.getNotificationChannels(pkg, uid, false).getList();
+        assertEquals(2, channels.size());   // Default channel + non-deleted channel
+        for (NotificationChannel nc : channels) {
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+                compareChannels(channel2, nc);
+            }
+        }
+
+        // Returns deleted channels too
+        channels =  mHelper.getNotificationChannels(pkg, uid, true).getList();
+        assertEquals(3, channels.size());               // Includes default channel
+        for (NotificationChannel nc : channels) {
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+                compareChannels(channelMap.get(nc.getId()), nc);
+            }
+        }
+    }
+
+    @Test
+    public void testUpdateDeletedChannels() throws Exception {
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(pkg, uid, channel, true);
+
+        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
+
+        channel.setSound(new Uri.Builder().scheme("test").build());
+        try {
+            mHelper.updateNotificationChannel(pkg, uid, channel);
+            fail("Updated deleted channel");
+        } catch (IllegalArgumentException e) {
+            // :)
+        }
+
+        try {
+            mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel);
+            fail("Updated deleted channel");
+        } catch (IllegalArgumentException e) {
+            // :)
+        }
+    }
+
+    @Test
+    public void testCreateDeletedChannel() throws Exception {
+        long[] vibration = new long[] {100, 67, 145, 156};
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+        channel.setVibrationPattern(vibration);
+
+        mHelper.createNotificationChannel(pkg, uid, channel, true);
+        mHelper.deleteNotificationChannel(pkg, uid, channel.getId());
+
+        NotificationChannel newChannel = new NotificationChannel(
+                channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
+        newChannel.setVibrationPattern(new long[] {100});
+
+        mHelper.createNotificationChannel(pkg, uid, newChannel, true);
+
+        // No long deleted, using old settings
+        compareChannels(channel,
+                mHelper.getNotificationChannel(pkg, uid, newChannel.getId(), false));
+    }
+
+    @Test
+    public void testCreateChannel_alreadyExists() throws Exception {
+        long[] vibration = new long[] {100, 67, 145, 156};
+        NotificationChannel channel =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+        channel.setVibrationPattern(vibration);
+
+        mHelper.createNotificationChannel(pkg, uid, channel, true);
+
+        NotificationChannel newChannel = new NotificationChannel(
+                channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
+        newChannel.setVibrationPattern(new long[] {100});
+
+        mHelper.createNotificationChannel(pkg, uid, newChannel, true);
+
+        // Old settings not overridden
+        compareChannels(channel,
+                mHelper.getNotificationChannel(pkg, uid, newChannel.getId(), false));
+    }
+
+    @Test
+    public void testPermanentlyDeleteChannels() throws Exception {
+        NotificationChannel channel1 =
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        NotificationChannel channel2 =
+                new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
+
+        mHelper.createNotificationChannel(pkg, uid, channel1, true);
+        mHelper.createNotificationChannel(pkg, uid, channel2, false);
+
+        mHelper.permanentlyDeleteNotificationChannels(pkg, uid);
+
+        // Only default channel remains
+        assertEquals(1, mHelper.getNotificationChannels(pkg, uid, true).getList().size());
+    }
+
+    @Test
+    public void testOnPackageChanged_packageRemoval() throws Exception {
+        // Deleted
+        NotificationChannel channel1 =
+                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(pkg, uid, channel1, true);
+
+        mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
+
+        assertEquals(0, mHelper.getNotificationChannels(pkg, uid, true).getList().size());
+
+        // Not deleted
+        mHelper.createNotificationChannel(pkg, uid, channel1, true);
+
+        mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid});
+        assertEquals(2, mHelper.getNotificationChannels(pkg, uid, false).getList().size());
+    }
 }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 1393615..6c7f146 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -18,6 +18,7 @@
         package="com.android.frameworks.servicestests">
 
     <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
@@ -65,6 +66,24 @@
           </intent-filter>
         </service>
 
+        <service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
+            android:exported="false">
+          <intent-filter>
+            <action android:name="android.accounts.AccountAuthenticator" />
+          </intent-filter>
+          <meta-data android:name="android.accounts.AccountAuthenticator"
+              android:resource="@xml/test_account_type1_authenticator" />
+        </service>
+
+        <service android:name="com.android.server.accounts.TestAccountType2AuthenticatorService"
+            android:exported="false">
+          <intent-filter>
+            <action android:name="android.accounts.AccountAuthenticator" />
+          </intent-filter>
+          <meta-data android:name="android.accounts.AccountAuthenticator"
+              android:resource="@xml/test_account_type2_authenticator" />
+        </service>
+
         <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
                 android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
@@ -117,7 +136,9 @@
         <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
 
         <activity android:name="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="true" android:exported="true" />
+                 android:enabled="true" android:exported="true" />
+
+        <activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
 
         <activity-alias android:name="a.ShortcutEnabled"
             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
@@ -138,6 +159,12 @@
             android:enabled="true" android:exported="true">
             <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_1"/>
         </activity-alias>
+        <activity-alias android:name="a.ShortcutConfigActivity"
+                        android:targetActivity="com.android.server.pm.ShortcutTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+            </intent-filter>
+        </activity-alias>
 
         <activity-alias android:name="a.DisabledMain"
             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
index 2f9d06c..121c1de 100644
--- a/services/tests/servicestests/res/values/strings.xml
+++ b/services/tests/servicestests/res/values/strings.xml
@@ -21,4 +21,8 @@
     <string name="shortcut_title2"></string>
     <string name="shortcut_text2"></string>
     <string name="shortcut_disabled_message2"></string>
+    <string name="test_account_type1_authenticator_label">AccountManagerService Test Account Type1</string>
+    <string name="test_account_type2_authenticator_label">AccountManagerService Test Account Type2</string>
+    <string name="test_account_type1">com.android.server.accounts.account_manager_service_test.account.type1</string>
+    <string name="test_account_type2">com.android.server.accounts.account_manager_service_test.account.type2</string>
 </resources>
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml b/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml
similarity index 62%
copy from packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
copy to services/tests/servicestests/res/xml/test_account_type1_authenticator.xml
index 387ca29..0c531de 100644
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
+++ b/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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,11 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="@string/test_account_type1"
+    android:icon="@drawable/icon1"
+    android:smallIcon="@drawable/icon1"
+    android:label="@string/test_account_type1_authenticator_label" />
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml b/services/tests/servicestests/res/xml/test_account_type2_authenticator.xml
similarity index 62%
copy from packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
copy to services/tests/servicestests/res/xml/test_account_type2_authenticator.xml
index 387ca29..f88eeb9 100644
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_root.xml
+++ b/services/tests/servicestests/res/xml/test_account_type2_authenticator.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 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,11 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="alpha"
-        android:valueFrom="0.3"
-        android:valueTo="1.0"
-        android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="@string/test_account_type2"
+    android:icon="@drawable/icon1"
+    android:smallIcon="@drawable/icon1"
+    android:label="@string/test_account_type2_authenticator_label" />
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 75d9c39..43c8957 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -144,7 +144,7 @@
         configuration.SSID = "NetworkScoreServiceTest_SSID";
         configuration.BSSID = "NetworkScoreServiceTest_BSSID";
         mRecommendationRequest = new RecommendationRequest.Builder()
-            .setCurrentRecommendedWifiConfig(configuration).build();
+            .setDefaultWifiConfig(configuration).build();
         mOnResultListener = new OnResultListener();
         mRemoteCallback = new RemoteCallback(mOnResultListener);
         Settings.Global.putLong(mContentResolver,
@@ -240,7 +240,7 @@
         final RecommendationResult result =
                 mNetworkScoreService.requestRecommendation(mRecommendationRequest);
         assertNotNull(result);
-        assertEquals(mRecommendationRequest.getCurrentSelectedConfig(),
+        assertEquals(mRecommendationRequest.getDefaultWifiConfig(),
                 result.getWifiConfiguration());
     }
 
@@ -255,7 +255,7 @@
         final RecommendationResult result =
                 mNetworkScoreService.requestRecommendation(mRecommendationRequest);
         assertNotNull(result);
-        assertEquals(mRecommendationRequest.getCurrentSelectedConfig(),
+        assertEquals(mRecommendationRequest.getDefaultWifiConfig(),
                 result.getWifiConfiguration());
     }
 
@@ -290,12 +290,12 @@
     @Test
     public void testRequestRecommendationAsync_noPermission() throws Exception {
         doThrow(new SecurityException()).when(mContext)
-                .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+                .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
                         anyString());
         try {
             mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
                     mRemoteCallback);
-            fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+            fail("REQUEST_NETWORK_SCORES not enforced.");
         } catch (SecurityException e) {
             // expected
         }
@@ -327,7 +327,7 @@
         RecommendationResult result =
                 mOnResultListener.receivedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT);
         assertTrue(result.hasRecommendation());
-        assertEquals(mRecommendationRequest.getCurrentSelectedConfig().SSID,
+        assertEquals(mRecommendationRequest.getDefaultWifiConfig().SSID,
                 result.getWifiConfiguration().SSID);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountAuthenticatorDummyActivity.java b/services/tests/servicestests/src/com/android/server/accounts/AccountAuthenticatorDummyActivity.java
new file mode 100644
index 0000000..8a14e1b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountAuthenticatorDummyActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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.accounts;
+
+import android.accounts.AccountAuthenticatorResponse;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Activity used by {@link com.android.server.accounts.TestAccountAuthenticator} to test the
+ * behavior of {@link AccountManagerService} when authenticator returns intent.
+ */
+public class AccountAuthenticatorDummyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Intent intent = getIntent();
+        AccountAuthenticatorResponse response =
+                intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK);
+        Intent result = intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT);
+        if (response != null) {
+            response.onResult(result.getExtras());
+        }
+        setResult(RESULT_OK, result);
+        finish();
+    }
+}
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 c74cda6..a600e69 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -17,30 +17,47 @@
 package com.android.server.accounts;
 
 import static android.database.sqlite.SQLiteDatabase.deleteDatabase;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.accounts.AccountManagerInternal;
 import android.accounts.AuthenticatorDescription;
+import android.accounts.CantAddAccountActivity;
+import android.accounts.IAccountManagerResponse;
 import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.INotificationManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.content.pm.RegisteredServicesCacheListener;
+import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
@@ -48,9 +65,18 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import com.android.frameworks.servicestests.R;
+import com.android.server.LocalServices;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -61,6 +87,20 @@
 public class AccountManagerServiceTest extends AndroidTestCase {
     private static final String TAG = AccountManagerServiceTest.class.getSimpleName();
 
+    @Mock private Context mMockContext;
+    @Mock private AppOpsManager mMockAppOpsManager;
+    @Mock private UserManager mMockUserManager;
+    @Mock private PackageManager mMockPackageManager;
+    @Mock private DevicePolicyManagerInternal mMockDevicePolicyManagerInternal;
+    @Mock private DevicePolicyManager mMockDevicePolicyManager;
+    @Mock private IAccountManagerResponse mMockAccountManagerResponse;
+    @Mock private IBinder mMockBinder;
+    @Mock private INotificationManager mMockNotificationManager;
+
+    @Captor private ArgumentCaptor<Intent> mIntentCaptor;
+    @Captor private ArgumentCaptor<Bundle> mBundleCaptor;
+
+    private static final int LATCH_TIMEOUT_MS = 500;
     private static final String PREN_DB = "pren.db";
     private static final String DE_DB = "de.db";
     private static final String CE_DB = "ce.db";
@@ -69,10 +109,29 @@
 
     @Override
     protected void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                    .thenReturn(PackageManager.SIGNATURE_MATCH);
+        final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
+        when(mMockUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager);
+        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+        when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
+                Context.APP_OPS_SERVICE);
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+        Bundle bundle = new Bundle();
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockAccountManagerResponse.asBinder()).thenReturn(mMockBinder);
+
         Context realTestContext = getContext();
-        MyMockContext mockContext = new MyMockContext(realTestContext);
+        MyMockContext mockContext = new MyMockContext(realTestContext, mMockContext);
         setContext(mockContext);
-        mTestInjector = new TestInjector(realTestContext, mockContext);
+        mTestInjector = new TestInjector(realTestContext, mockContext, mMockNotificationManager);
         mAms = new AccountManagerService(mTestInjector);
     }
 
@@ -104,12 +163,12 @@
     @SmallTest
     public void testCheckAddAccount() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
-        Account a21 = new Account("account2", "type1");
-        Account a31 = new Account("account3", "type1");
-        Account a12 = new Account("account1", "type2");
-        Account a22 = new Account("account2", "type2");
-        Account a32 = new Account("account3", "type2");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a21 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a31 = new Account("account3", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
+        Account a22 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
+        Account a32 = new Account("account3", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a11, "p11", null);
         mAms.addAccountExplicitly(a12, "p12", null);
         mAms.addAccountExplicitly(a21, "p21", null);
@@ -127,7 +186,8 @@
         assertEquals(a22, accounts[4]);
         assertEquals(a32, accounts[5]);
 
-        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
+        accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(3, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -136,7 +196,8 @@
 
         mAms.removeAccountInternal(a21);
 
-        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
+        accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(2, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -146,8 +207,8 @@
     @SmallTest
     public void testPasswords() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
-        Account a12 = new Account("account1", "type2");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a11, "p11", null);
         mAms.addAccountExplicitly(a12, "p12", null);
 
@@ -163,12 +224,12 @@
     @SmallTest
     public void testUserdata() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
         Bundle u11 = new Bundle();
         u11.putString("a", "a_a11");
         u11.putString("b", "b_a11");
         u11.putString("c", "c_a11");
-        Account a12 = new Account("account1", "type2");
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         Bundle u12 = new Bundle();
         u12.putString("a", "a_a12");
         u12.putString("b", "b_a12");
@@ -197,8 +258,8 @@
     @SmallTest
     public void testAuthtokens() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
-        Account a12 = new Account("account1", "type2");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a11, "p11", null);
         mAms.addAccountExplicitly(a12, "p12", null);
 
@@ -232,8 +293,8 @@
     @SmallTest
     public void testRemovedAccountSync() throws Exception {
         unlockSystemUser();
-        Account a1 = new Account("account1", "type1");
-        Account a2 = new Account("account2", "type2");
+        Account a1 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a2 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a1, "p1", null);
         mAms.addAccountExplicitly(a2, "p2", null);
 
@@ -292,6 +353,944 @@
                 new File(ceDatabaseName).exists());
     }
 
+    @SmallTest
+    public void testStartAddAccountSessionWithNullResponse() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.startAddAccountSession(
+                null, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionWithNullAccountType() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.startAddAccountSession(
+                    mMockAccountManagerResponse, // response
+                    null, // accountType
+                    "authTokenType",
+                    null, // requiredFeatures
+                    true, // expectActivityLaunch
+                    null); // optionsIn
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountNoDPM() throws Exception {
+        unlockSystemUser();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+        verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+
+        // verify the intent for default CantAddAccountActivity is sent.
+        Intent intent = mIntentCaptor.getValue();
+        assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+        assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+                AccountManager.ERROR_CODE_USER_RESTRICTED);
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountWithDPM() throws Exception {
+        unlockSystemUser();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.addService(
+                DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+        when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+                anyInt(), anyString())).thenReturn(new Intent());
+        when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+                anyInt(), anyBoolean())).thenReturn(new Intent());
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+        verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM));
+        verify(mMockDevicePolicyManagerInternal).createUserRestrictionSupportIntent(
+                anyInt(), anyString());
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountForTypeNoDPM() throws Exception {
+        unlockSystemUser();
+        when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+                .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+        verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+
+        // verify the intent for default CantAddAccountActivity is sent.
+        Intent intent = mIntentCaptor.getValue();
+        assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+        assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+                AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountForTypeWithDPM() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+                .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.addService(
+                DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+        when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+                anyInt(), anyString())).thenReturn(new Intent());
+        when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+                anyInt(), anyBoolean())).thenReturn(new Intent());
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+        verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM));
+        verify(mMockDevicePolicyManagerInternal).createShowAdminSupportIntent(
+                anyInt(), anyBoolean());
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionSuccessWithoutPasswordForwarding() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                false, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // Assert password is not returned
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+                result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionSuccessWithPasswordForwarding() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                false, // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // Assert password is returned
+        assertEquals(result.getString(AccountManager.KEY_PASSWORD),
+                AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+                result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionReturnWithInvalidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionReturnWithValidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+        assertNotNull(intent);
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionError() throws Exception {
+        unlockSystemUser();
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                false, // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionWithNullResponse() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.startUpdateCredentialsSession(
+                null, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+                "authTokenType",
+                true, // expectActivityLaunch
+                null); // optionsIn
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionWithNullAccount() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.startUpdateCredentialsSession(
+                mMockAccountManagerResponse, // response
+                null,
+                "authTokenType",
+                true, // expectActivityLaunch
+                null); // optionsIn
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionSuccessWithoutPasswordForwarding()
+            throws Exception {
+        unlockSystemUser();
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+            AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+        mAms.startUpdateCredentialsSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+                "authTokenType",
+                false, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // Assert password is not returned
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+                result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionSuccessWithPasswordForwarding() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+            AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+        mAms.startUpdateCredentialsSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+                "authTokenType",
+                false, // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // Assert password is returned
+        assertEquals(result.getString(AccountManager.KEY_PASSWORD),
+                AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+                result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionReturnWithInvalidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+        mAms.startUpdateCredentialsSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+                "authTokenType",
+                true,  // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionReturnWithValidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+        mAms.startUpdateCredentialsSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+                "authTokenType",
+                true,  // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+        assertNotNull(intent);
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+    }
+
+    @SmallTest
+    public void testStartUpdateCredentialsSessionError() throws Exception {
+        unlockSystemUser();
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+
+        mAms.startUpdateCredentialsSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+                "authTokenType",
+                true,  // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserWithNullResponse() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.finishSessionAsUser(
+                null, // response
+                createEncryptedSessionBundle(
+                        AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+                false, // expectActivityLaunch
+                createAppBundle(), // appInfo
+                UserHandle.USER_SYSTEM);
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserWithNullSessionBundle() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.finishSessionAsUser(
+                mMockAccountManagerResponse, // response
+                null, // sessionBundle
+                false, // expectActivityLaunch
+                createAppBundle(), // appInfo
+                UserHandle.USER_SYSTEM);
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserUserCannotModifyAccountNoDPM() throws Exception {
+        unlockSystemUser();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+        mAms.finishSessionAsUser(
+            mMockAccountManagerResponse, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            2); // fake user id
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+        verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.of(2)));
+
+        // verify the intent for default CantAddAccountActivity is sent.
+        Intent intent = mIntentCaptor.getValue();
+        assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+        assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+                AccountManager.ERROR_CODE_USER_RESTRICTED);
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserUserCannotModifyAccountWithDPM() throws Exception {
+        unlockSystemUser();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.addService(
+                DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+        when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+                anyInt(), anyString())).thenReturn(new Intent());
+        when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+                anyInt(), anyBoolean())).thenReturn(new Intent());
+
+        mAms.finishSessionAsUser(
+            mMockAccountManagerResponse, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            2); // fake user id
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+        verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.of(2)));
+        verify(mMockDevicePolicyManagerInternal).createUserRestrictionSupportIntent(
+                anyInt(), anyString());
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserWithBadSessionBundle() throws Exception {
+        unlockSystemUser();
+
+        Bundle badSessionBundle = new Bundle();
+        badSessionBundle.putString("any", "any");
+        mAms.finishSessionAsUser(
+            mMockAccountManagerResponse, // response
+            badSessionBundle, // sessionBundle
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            2); // fake user id
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_BAD_REQUEST), anyString());
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserWithBadAccountType() throws Exception {
+        unlockSystemUser();
+
+        mAms.finishSessionAsUser(
+            mMockAccountManagerResponse, // response
+            createEncryptedSessionBundleWithNoAccountType(
+                    AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            2); // fake user id
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_BAD_ARGUMENTS), anyString());
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserUserCannotModifyAccountForTypeNoDPM() throws Exception {
+        unlockSystemUser();
+        when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+                .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+        mAms.finishSessionAsUser(
+            mMockAccountManagerResponse, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            2); // fake user id
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+        verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.of(2)));
+
+        // verify the intent for default CantAddAccountActivity is sent.
+        Intent intent = mIntentCaptor.getValue();
+        assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+        assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+                AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserUserCannotModifyAccountForTypeWithDPM() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+                .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.addService(
+                DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+        when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+                anyInt(), anyString())).thenReturn(new Intent());
+        when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+                anyInt(), anyBoolean())).thenReturn(new Intent());
+
+        mAms.finishSessionAsUser(
+            mMockAccountManagerResponse, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            2); // fake user id
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+        verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.of(2)));
+        verify(mMockDevicePolicyManagerInternal).createShowAdminSupportIntent(
+                anyInt(), anyBoolean());
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserSuccess() throws Exception {
+        unlockSystemUser();
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        mAms.finishSessionAsUser(
+            response, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            UserHandle.USER_SYSTEM);
+
+        waitForLatch(latch);
+        // Verify notification is cancelled
+        verify(mMockNotificationManager).cancelNotificationWithTag(
+                anyString(), anyString(), anyInt(), anyInt());
+
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is decrypted and hence data is visible.
+        assertEquals(AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1,
+                sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // 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");
+
+        // Verify response data
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME,
+                result.getString(AccountManager.KEY_ACCOUNT_NAME));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserReturnWithInvalidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+
+        mAms.finishSessionAsUser(
+            response, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE),
+            true, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            UserHandle.USER_SYSTEM);
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserReturnWithValidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+
+        mAms.finishSessionAsUser(
+            response, // response
+            createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE),
+            true, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            UserHandle.USER_SYSTEM);
+
+        waitForLatch(latch);
+
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+        assertNotNull(intent);
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+    }
+
+    @SmallTest
+    public void testFinishSessionAsUserError() throws Exception {
+        unlockSystemUser();
+        Bundle sessionBundle = createEncryptedSessionBundleWithError(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+
+        mAms.finishSessionAsUser(
+            response, // response
+            sessionBundle,
+            false, // expectActivityLaunch
+            createAppBundle(), // appInfo
+            UserHandle.USER_SYSTEM);
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+    }
+
+    @SmallTest
+    public void testIsCredentialsUpdatedSuggestedWithNullResponse() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.isCredentialsUpdateSuggested(
+                null, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+                AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testIsCredentialsUpdatedSuggestedWithNullAccount() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.isCredentialsUpdateSuggested(
+                mMockAccountManagerResponse,
+                null, // account
+                AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testIsCredentialsUpdatedSuggestedWithEmptyStatusToken() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.isCredentialsUpdateSuggested(
+                mMockAccountManagerResponse,
+                AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+                null);
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testIsCredentialsUpdatedSuggestedError() throws Exception {
+        unlockSystemUser();
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+
+        mAms.isCredentialsUpdateSuggested(
+            response,
+            AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+            AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+    }
+
+    @SmallTest
+    public void testIsCredentialsUpdatedSuggestedSuccess() throws Exception {
+        unlockSystemUser();
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+
+        mAms.isCredentialsUpdateSuggested(
+            response,
+            AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+            AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        boolean needUpdate = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+        assertTrue(needUpdate);
+    }
+
+    private void waitForLatch(CountDownLatch latch) {
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            throw new IllegalStateException("Should not throw an InterruptedException", e);
+        }
+    }
+
+    private Bundle encryptBundleWithCryptoHelper(Bundle sessionBundle) {
+        Bundle encryptedBundle = null;
+        try {
+            CryptoHelper cryptoHelper = CryptoHelper.getInstance();
+            encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
+        } catch (GeneralSecurityException e) {
+            throw new IllegalStateException("Failed to encrypt session bundle.", e);
+        }
+        return encryptedBundle;
+    }
+
+    private Bundle createEncryptedSessionBundle(final String accountName) {
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(
+                AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+                AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        sessionBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.session.package");
+        return encryptBundleWithCryptoHelper(sessionBundle);
+    }
+
+    private Bundle createEncryptedSessionBundleWithError(final String accountName) {
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(
+                AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+                AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        sessionBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.session.package");
+        sessionBundle.putInt(
+                AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        return encryptBundleWithCryptoHelper(sessionBundle);
+    }
+
+    private Bundle createEncryptedSessionBundleWithNoAccountType(final String accountName) {
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+        sessionBundle.putString(
+                AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+                AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+        sessionBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.session.package");
+        return encryptBundleWithCryptoHelper(sessionBundle);
+    }
+
+    private Bundle createAppBundle() {
+        Bundle appBundle = new Bundle();
+        appBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.package");
+        return appBundle;
+    }
+
+    private Bundle createOptionsWithAccountName(final String accountName) {
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(
+                AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+                AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Bundle options = new Bundle();
+        options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE,
+                sessionBundle);
+        options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD,
+                AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+        return options;
+    }
+
     private int readNumberOfAccountsFromDbFile(Context context, String dbName) {
         SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null);
         try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) {
@@ -310,78 +1309,34 @@
         return intent;
     }
 
-    static class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
-        private ArrayList<ServiceInfo<AuthenticatorDescription>> mServices;
-
-        MockAccountAuthenticatorCache() {
-            mServices = new ArrayList<>();
-            AuthenticatorDescription d1 = new AuthenticatorDescription("type1", "p1", 0, 0, 0, 0);
-            AuthenticatorDescription d2 = new AuthenticatorDescription("type2", "p2", 0, 0, 0, 0);
-            mServices.add(new ServiceInfo<>(d1, null, null));
-            mServices.add(new ServiceInfo<>(d2, null, null));
-        }
-
-        @Override
-        public ServiceInfo<AuthenticatorDescription> getServiceInfo(
-                AuthenticatorDescription type, int userId) {
-            for (ServiceInfo<AuthenticatorDescription> service : mServices) {
-                if (service.type.equals(type)) {
-                    return service;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public Collection<ServiceInfo<AuthenticatorDescription>> getAllServices(int userId) {
-            return mServices;
-        }
-
-        @Override
-        public void dump(
-                final FileDescriptor fd, final PrintWriter fout, final String[] args, int userId) {
-        }
-
-        @Override
-        public void setListener(
-                final RegisteredServicesCacheListener<AuthenticatorDescription> listener,
-                final Handler handler) {
-        }
-
-        @Override
-        public void invalidateCache(int userId) {
-        }
-
-        @Override
-        public void updateServices(int userId) {
-        }
-    }
-
     static class MyMockContext extends MockContext {
         private Context mTestContext;
-        private AppOpsManager mAppOpsManager;
-        private UserManager mUserManager;
-        private PackageManager mPackageManager;
+        private Context mMockContext;
 
-        MyMockContext(Context testContext) {
+        MyMockContext(Context testContext, Context mockContext) {
             this.mTestContext = testContext;
-            this.mAppOpsManager = mock(AppOpsManager.class);
-            this.mUserManager = mock(UserManager.class);
-            this.mPackageManager = mock(PackageManager.class);
-            when(mPackageManager.checkSignatures(anyInt(), anyInt()))
-                    .thenReturn(PackageManager.SIGNATURE_MATCH);
-            final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
-            when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
+            this.mMockContext = mockContext;
         }
 
         @Override
         public int checkCallingOrSelfPermission(final String permission) {
-            return PackageManager.PERMISSION_GRANTED;
+            return mMockContext.checkCallingOrSelfPermission(permission);
+        }
+
+        @Override
+        public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+                UserHandle user) {
+            return mTestContext.bindServiceAsUser(service, conn, flags, user);
+        }
+
+        @Override
+        public void unbindService(ServiceConnection conn) {
+            mTestContext.unbindService(conn);
         }
 
         @Override
         public PackageManager getPackageManager() {
-            return mPackageManager;
+            return mMockContext.getPackageManager();
         }
 
         @Override
@@ -391,56 +1346,68 @@
 
         @Override
         public Object getSystemService(String name) {
-            if (Context.APP_OPS_SERVICE.equals(name)) {
-                return mAppOpsManager;
-            } else if( Context.USER_SERVICE.equals(name)) {
-                return mUserManager;
-            }
-            return null;
+            return mMockContext.getSystemService(name);
         }
 
         @Override
         public String getSystemServiceName(Class<?> serviceClass) {
-            if (AppOpsManager.class.equals(serviceClass)) {
-                return Context.APP_OPS_SERVICE;
-            }
-            return null;
+            return mMockContext.getSystemServiceName(serviceClass);
+        }
+
+        @Override
+        public void startActivityAsUser(Intent intent, UserHandle user) {
+            mMockContext.startActivityAsUser(intent, user);
         }
 
         @Override
         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
-            return null;
+            return mMockContext.registerReceiver(receiver, filter);
         }
 
         @Override
         public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
                 IntentFilter filter, String broadcastPermission, Handler scheduler) {
-            return null;
+            return mMockContext.registerReceiverAsUser(
+                    receiver, user, filter, broadcastPermission, scheduler);
         }
 
         @Override
         public SQLiteDatabase openOrCreateDatabase(String file, int mode,
                 SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
-            Log.i(TAG, "openOrCreateDatabase " + file + " mode " + mode);
             return mTestContext.openOrCreateDatabase(file, mode, factory,errorHandler);
         }
 
         @Override
         public void sendBroadcastAsUser(Intent intent, UserHandle user) {
-            Log.i(TAG, "sendBroadcastAsUser " + intent + " " + user);
+            mMockContext.sendBroadcastAsUser(intent, user);
         }
 
         @Override
         public String getOpPackageName() {
-            return null;
+            return mMockContext.getOpPackageName();
+        }
+    }
+
+    static class TestAccountAuthenticatorCache extends AccountAuthenticatorCache {
+        public TestAccountAuthenticatorCache(Context realContext) {
+            super(realContext);
+        }
+
+        @Override
+        protected File getUserSystemDirectory(int userId) {
+            return new File(mContext.getCacheDir(), "authenticator");
         }
     }
 
     static class TestInjector extends AccountManagerService.Injector {
         private Context mRealContext;
-        TestInjector(Context realContext, MyMockContext mockContext) {
+        private INotificationManager mMockNotificationManager;
+        TestInjector(Context realContext,
+                Context mockContext,
+                INotificationManager mockNotificationManager) {
             super(mockContext);
             mRealContext = realContext;
+            mMockNotificationManager = mockNotificationManager;
         }
 
         @Override
@@ -454,7 +1421,7 @@
 
         @Override
         IAccountAuthenticatorCache getAccountAuthenticatorCache() {
-            return new MockAccountAuthenticatorCache();
+            return new TestAccountAuthenticatorCache(mRealContext);
         }
 
         @Override
@@ -474,7 +1441,34 @@
 
         @Override
         INotificationManager getNotificationManager() {
-            return mock(INotificationManager.class);
+            return mMockNotificationManager;
+        }
+    }
+
+    class Response extends IAccountManagerResponse.Stub {
+        private CountDownLatch mLatch;
+        private IAccountManagerResponse mMockResponse;
+        public Response(CountDownLatch latch, IAccountManagerResponse mockResponse) {
+            mLatch = latch;
+            mMockResponse = mockResponse;
+        }
+
+        @Override
+        public void onResult(Bundle bundle) {
+            try {
+                mMockResponse.onResult(bundle);
+            } catch (RemoteException e) {
+            }
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onError(int code, String message) {
+            try {
+                mMockResponse.onError(code, message);
+            } catch (RemoteException e) {
+            }
+            mLatch.countDown();
         }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
new file mode 100644
index 0000000..9a2c190
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -0,0 +1,70 @@
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Constants shared between test AccountAuthenticators and AccountManagerServiceTest.
+ */
+public final class AccountManagerServiceTestFixtures {
+    public static final String KEY_ACCOUNT_NAME = "account_manager_service_test:account_name_key";
+    public static final String KEY_ACCOUNT_SESSION_BUNDLE =
+            "account_manager_service_test:account_session_bundle_key";
+    public static final String KEY_ACCOUNT_STATUS_TOKEN =
+            "account_manager_service_test:account_status_token_key";
+    public static final String KEY_ACCOUNT_PASSWORD =
+            "account_manager_service_test:account_password_key";
+
+    public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com";
+    public static final String ACCOUNT_NAME_INTERVENE = "intervene@fixture.com";
+    public static final String ACCOUNT_NAME_ERROR = "error@fixture.com";
+
+    public static final String ACCOUNT_NAME =
+            "com.android.server.accounts.account_manager_service_test.account.name";
+    public static final String ACCOUNT_TYPE_1 =
+            "com.android.server.accounts.account_manager_service_test.account.type1";
+    public static final String ACCOUNT_TYPE_2 =
+            "com.android.server.accounts.account_manager_service_test.account.type2";
+    public static final String ACCOUNT_FAKE_TYPE =
+            "com.android.server.accounts.account_manager_service_test.account.type.fake";
+
+    public static final String ACCOUNT_STATUS_TOKEN =
+            "com.android.server.accounts.account_manager_service_test.account.status.token";
+
+    public static final String ACCOUNT_PASSWORD =
+            "com.android.server.accounts.account_manager_service_test.account.password";
+    public static final String KEY_RESULT = "account_manager_service_test:result";
+    public static final String KEY_CALLBACK = "account_manager_service_test:callback";
+
+    public static final Account ACCOUNT_SUCCESS =
+            new Account(ACCOUNT_NAME_SUCCESS, ACCOUNT_TYPE_1);
+    public static final Account ACCOUNT_INTERVENE =
+            new Account(ACCOUNT_NAME_INTERVENE, ACCOUNT_TYPE_1);
+    public static final Account ACCOUNT_ERROR =
+            new Account(ACCOUNT_NAME_ERROR, ACCOUNT_TYPE_1);
+
+    public static final String SESSION_DATA_NAME_1 = "session.data.name.1";
+    public static final String SESSION_DATA_VALUE_1 = "session.data.value.1";
+
+    public static final String ERROR_MESSAGE =
+        "com.android.server.accounts.account_manager_service_test.error.message";
+
+    private AccountManagerServiceTestFixtures() {}
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
index 97adbe6..38b3735 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
@@ -26,7 +26,7 @@
 class PreNTestDatabaseHelper extends SQLiteOpenHelper {
 
     public static final String TOKEN_STRING = "token-string-123";
-    public static final String ACCOUNT_TYPE = "type1";
+    public static final String ACCOUNT_TYPE = AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2;
     public static final String ACCOUNT_NAME = "account@" + ACCOUNT_TYPE;
     public static final String ACCOUNT_PASSWORD = "Password";
     public static final String TOKEN_TYPE = "SID";
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
new file mode 100644
index 0000000..8ec6176
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -0,0 +1,317 @@
+/*
+ * 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.accounts;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.frameworks.servicestests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This authenticator is to mock account authenticator to test AccountManagerService.
+ */
+public class TestAccountType1Authenticator extends AbstractAccountAuthenticator {
+    private final AtomicInteger mTokenCounter  = new AtomicInteger(0);
+
+    private final String mAccountType;
+    private final Context mContext;
+
+    public TestAccountType1Authenticator(Context context, String accountType) {
+        super(context);
+        mAccountType = accountType;
+        mContext = context;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        throw new UnsupportedOperationException(
+                "editProperties is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle addAccount(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, "test_account@test.com");
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
+        return result;
+    }
+
+    @Override
+    public Bundle confirmCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "confirmCredentials is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle getAuthToken(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "getAuthToken is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        throw new UnsupportedOperationException(
+                "getAuthTokenLabel is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle updateCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+        return result;
+    }
+
+    @Override
+    public Bundle hasFeatures(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String[] features) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "hasFeatures is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle startAddAccountSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        String password = null;
+        if (options != null) {
+            accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+            sessionBundle = options.getBundle(
+                    AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+            password = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD, password);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.equals(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD, password);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+                    eventualActivityResultData);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            fillResultWithError(result, options);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Bundle startUpdateCredentialsSession(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options)
+            throws NetworkErrorException {
+
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+            sessionBundle = options.getBundle(
+            AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD,
+                    AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.equals(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+                    AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+                    eventualActivityResultData);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            fillResultWithError(result, options);
+        }
+        return result;
+    }
+
+    @Override
+    public Bundle finishSession(AccountAuthenticatorResponse response,
+            String accountType,
+            Bundle sessionBundle) throws NetworkErrorException {
+
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        if (sessionBundle != null) {
+            accountName = sessionBundle.getString(
+            AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // add sessionBundle into result for verification purpose
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            // fill bundle with a success result.
+            result.putString(AccountManager.KEY_ACCOUNT_NAME,
+                    AccountManagerServiceTestFixtures.ACCOUNT_NAME);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.equals(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME,
+                    AccountManagerServiceTestFixtures.ACCOUNT_NAME);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+                    eventualActivityResultData);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            fillResultWithError(result, sessionBundle);
+        }
+        return result;
+    }
+
+    @Override
+    public Bundle isCredentialsUpdateSuggested(
+            final AccountAuthenticatorResponse response,
+            Account account,
+            String statusToken) throws NetworkErrorException {
+
+        Bundle result = new Bundle();
+        if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        } else {
+            // fill with error
+            fillResultWithError(
+                    result,
+                    AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                    AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        }
+
+        response.onResult(result);
+        return null;
+    }
+
+    private void fillResultWithError(Bundle result, Bundle options) {
+        int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+        String errorMsg = "Default Error Message";
+        if (options != null) {
+            errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+            errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+        }
+        fillResultWithError(result, errorCode, errorMsg);
+    }
+
+    private void fillResultWithError(Bundle result, int errorCode, String errorMsg) {
+        result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+        result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1AuthenticatorService.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1AuthenticatorService.java
new file mode 100644
index 0000000..acd1046
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1AuthenticatorService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.accounts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a test Mock Service for wrapping the TestAccountType1Authenticator
+ */
+public class TestAccountType1AuthenticatorService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        TestAccountType1Authenticator authenticator = new TestAccountType1Authenticator(
+                this, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        return authenticator.getIBinder();
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2Authenticator.java
new file mode 100644
index 0000000..4cbc8cb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2Authenticator.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.accounts;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.frameworks.servicestests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This authenticator is to mock account authenticator to test AccountManagerService.
+ */
+public class TestAccountType2Authenticator extends AbstractAccountAuthenticator {
+    private final AtomicInteger mTokenCounter  = new AtomicInteger(0);
+
+    private final String mAccountType;
+    private final Context mContext;
+
+    public TestAccountType2Authenticator(Context context, String accountType) {
+        super(context);
+        mAccountType = accountType;
+        mContext = context;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        throw new UnsupportedOperationException(
+                "editProperties is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle addAccount(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "addAccount is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle confirmCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "confirmCredentials is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle getAuthToken(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "getAuthToken is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        throw new UnsupportedOperationException(
+                "getAuthTokenLabel is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle updateCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "updateCredentials is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle hasFeatures(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String[] features) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "hasFeatures is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle startAddAccountSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "startAddAccountSession is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle startUpdateCredentialsSession(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options)
+            throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "startUpdateCredentialsSession is not supported " +
+                "by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle finishSession(AccountAuthenticatorResponse response,
+            String accountType,
+            Bundle sessionBundle) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "finishSession is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle isCredentialsUpdateSuggested(
+            final AccountAuthenticatorResponse response,
+            Account account,
+            String statusToken) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "isCredentialsUpdateSuggested is not supported " +
+                "by the TestAccountType2Authenticator");
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2AuthenticatorService.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2AuthenticatorService.java
new file mode 100644
index 0000000..b80dc78
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2AuthenticatorService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.accounts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a test Mock Service for wrapping the TestAccountType2Authenticator
+ */
+public class TestAccountType2AuthenticatorService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        TestAccountType2Authenticator authenticator = new TestAccountType2Authenticator(
+                this, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
+        return authenticator.getIBinder();
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 4886a5f..677e468 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -28,6 +29,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.appwidget.PendingHostUpdate;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContextWrapper;
@@ -39,11 +41,17 @@
 import android.os.UserHandle;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.RemoteViews;
 
+import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.server.LocalServices;
 
 import org.mockito.ArgumentCaptor;
 
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
 
 /**
  * Tests for {@link AppWidgetManager} and {@link AppWidgetServiceImpl}.
@@ -57,11 +65,15 @@
 @SmallTest
 public class AppWidgetServiceImplTest extends InstrumentationTestCase {
 
+    private static final int HOST_ID = 42;
+
     private TestContext mTestContext;
+    private String mPkgName;
     private AppWidgetServiceImpl mService;
     private AppWidgetManager mManager;
 
     private ShortcutServiceInternal mMockShortcutService;
+    private IAppWidgetHost mMockHost;
 
     @Override
     protected void setUp() throws Exception {
@@ -70,12 +82,13 @@
         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
 
         mTestContext = new TestContext();
+        mPkgName = mTestContext.getOpPackageName();
         mService = new AppWidgetServiceImpl(mTestContext);
         mManager = new AppWidgetManager(mTestContext, mService);
 
         mMockShortcutService = mock(ShortcutServiceInternal.class);
+        mMockHost = mock(IAppWidgetHost.class);
         LocalServices.addService(ShortcutServiceInternal.class, mMockShortcutService);
-
         mService.onStart();
     }
 
@@ -108,6 +121,142 @@
         assertEquals(provider, providerCaptor.getValue().provider);
     }
 
+    public void testProviderUpdatesReceived() throws Exception {
+        int widgetId = setupHostAndWidget();
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.updateAppWidget(widgetId, view);
+
+        flushMainThread();
+        verify(mMockHost, times(4)).updateAppWidget(eq(widgetId), any(RemoteViews.class));
+
+        reset(mMockHost);
+        mManager.notifyAppWidgetViewDataChanged(widgetId, 22);
+        flushMainThread();
+        verify(mMockHost, times(1)).viewDataChanged(eq(widgetId), eq(22));
+    }
+
+    public void testProviderUpdatesNotReceived() throws Exception {
+        int widgetId = setupHostAndWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.notifyAppWidgetViewDataChanged(widgetId, 22);
+
+        flushMainThread();
+        verify(mMockHost, times(0)).updateAppWidget(anyInt(), any(RemoteViews.class));
+        verify(mMockHost, times(0)).viewDataChanged(anyInt(), eq(22));
+    }
+
+    public void testNoUpdatesReceived_queueEmpty() {
+        int widgetId = setupHostAndWidget();
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.notifyAppWidgetViewDataChanged(widgetId, 22);
+        mService.stopListening(mPkgName, HOST_ID);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[0]).getList();
+        assertTrue(updates.isEmpty());
+    }
+
+    /**
+     * Sends dummy widget updates to {@link #mManager}.
+     * @param widgetId widget to update
+     * @param viewIds a list of view ids for which
+     *                {@link AppWidgetManager#notifyAppWidgetViewDataChanged} will be called
+     */
+    private void sendDummyUpdates(int widgetId, int... viewIds) {
+        Random r = new Random();
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        for (int i = r.nextInt(10) + 2; i >= 0; i--) {
+            mManager.updateAppWidget(widgetId, view);
+        }
+
+        for (int viewId : viewIds) {
+            mManager.notifyAppWidgetViewDataChanged(widgetId, viewId);
+            for (int i = r.nextInt(3); i >= 0; i--) {
+                mManager.updateAppWidget(widgetId, view);
+            }
+        }
+    }
+
+    public void testNoUpdatesReceived_queueNonEmpty_noWidgetId() {
+        int widgetId = setupHostAndWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[0]).getList();
+        assertTrue(updates.isEmpty());
+    }
+
+    public void testUpdatesReceived_queueNotEmpty_widgetIdProvided() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId}).getList();
+        // 3 updates corresponding to the first widget
+        assertEquals(3, updates.size());
+    }
+
+    public void testUpdatesReceived_queueNotEmpty_widgetIdProvided2() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId2}).getList();
+        // 4 updates corresponding to the second widget
+        assertEquals(4, updates.size());
+    }
+
+    public void testUpdatesReceived_queueNotEmpty_multipleWidgetIdProvided() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList();
+        // 3 updates for first widget and 4 for second
+        assertEquals(7, updates.size());
+    }
+
+    private int setupHostAndWidget() {
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[0]).getList();
+        assertTrue(updates.isEmpty());
+        return bindNewWidget();
+    }
+
+    private int bindNewWidget() {
+        ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
+        int widgetId = mService.allocateAppWidgetId(mPkgName, HOST_ID);
+        assertTrue(mManager.bindAppWidgetIdIfAllowed(widgetId, provider));
+        assertEquals(provider, mManager.getAppWidgetInfo(widgetId).provider);
+
+        return widgetId;
+    }
+
+    private void flushMainThread() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        new Handler(mTestContext.getMainLooper()).post(latch::countDown);
+        latch.await();
+    }
+
     private class TestContext extends ContextWrapper {
 
         public TestContext() {
@@ -125,5 +274,15 @@
         public void unregisterReceiver(BroadcastReceiver receiver) {
             // ignore.
         }
+
+        @Override
+        public void enforceCallingOrSelfPermission(String permission, String message) {
+            // ignore.
+        }
+
+        @Override
+        public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+            // ignore.
+        }
     }
 }
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 c3eb09d..8da47c8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.server.devicepolicy;
 
+import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
+
 import android.Manifest.permission;
 import android.app.Activity;
 import android.app.admin.DeviceAdminReceiver;
@@ -39,6 +43,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.test.MoreAsserts;
@@ -61,9 +66,11 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -928,9 +935,8 @@
 
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions()
-        );
+                eq(null),
+                eq(true), eq(CAMERA_NOT_DISABLED));
 
         assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
 
@@ -1287,7 +1293,8 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(defaultRestrictions),
-                MockUtils.checkUserRestrictions()
+                eq(true) /* isDeviceOwner */,
+                eq(CAMERA_NOT_DISABLED)
         );
         reset(mContext.userManagerInternal);
 
@@ -1296,21 +1303,21 @@
         }
 
         assertNoDeviceOwnerRestrictions();
+        reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-        );
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-        );
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1328,8 +1335,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                MockUtils.checkUserRestrictions()
-        );
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1345,8 +1351,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions()
-        );
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         assertNoDeviceOwnerRestrictions();
@@ -1358,42 +1363,38 @@
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
-                        UserManager.DISALLOW_UNMUTE_MICROPHONE)
-        );
+                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-
+        reset(mContext.userManagerInternal);
 
         // More tests.
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-        );
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_ADD_USER)
-        );
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.setCameraDisabled(admin1, true);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 // DISALLOW_CAMERA will be applied to both local and global.
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
-        );
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_DISABLED_GLOBALLY));
         reset(mContext.userManagerInternal);
 
         // Set up another DA and let it disable camera.  Now DISALLOW_CAMERA will only be applied
@@ -1407,11 +1408,10 @@
 
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                // DISALLOW_CAMERA will be applied to both local and global.
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+                // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_ADD_USER)
-        );
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_DISABLED_LOCALLY));
         reset(mContext.userManagerInternal);
         // TODO Make sure restrictions are written to the file.
     }
@@ -1429,8 +1429,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1438,8 +1437,7 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                         UserManager.DISALLOW_OUTGOING_CALLS),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1462,8 +1460,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1484,8 +1481,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1507,18 +1503,15 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                         UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.setCameraDisabled(admin1, true);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
-                        UserManager.DISALLOW_ADJUST_VOLUME,
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                         UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_DISABLED_LOCALLY));
         reset(mContext.userManagerInternal);
 
         // TODO Make sure restrictions are written to the file.
@@ -1558,7 +1551,8 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(defaultRestrictions),
-                MockUtils.checkUserRestrictions()
+                eq(true) /* isDeviceOwner */,
+                eq(CAMERA_NOT_DISABLED)
         );
         reset(mContext.userManagerInternal);
 
@@ -1600,7 +1594,8 @@
             verify(mContext.userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
-                MockUtils.checkUserRestrictions()
+                eq(true) /* isDeviceOwner */,
+                eq(CAMERA_NOT_DISABLED)
             );
             reset(mContext.userManagerInternal);
 
@@ -2124,8 +2119,37 @@
         setupDeviceOwner();
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
-        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
-        final long ONE_MINUTE = 60 * 1000;
+        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1);
+        final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
+        final long MIN_PLUS_ONE_MINUTE = MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE;
+        final long MAX_MINUS_ONE_MINUTE = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS
+                - ONE_MINUTE;
+
+        // verify that the minimum timeout cannot be modified on user builds (system property is
+        // not being read)
+        mContext.buildMock.isDebuggable = false;
+
+        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);
+
+        verify(mContext.systemProperties, never()).getLong(anyString(), anyLong());
+
+        // restore to the debuggable build state
+        mContext.buildMock.isDebuggable = true;
+
+        // Always return the default (second arg) when getting system property for long type
+        when(mContext.systemProperties.getLong(anyString(), anyLong())).thenAnswer(
+                new Answer<Long>() {
+                    @Override
+                    public Long answer(InvocationOnMock invocation) throws Throwable {
+                        return (Long) invocation.getArguments()[1];
+                    }
+                }
+        );
+
+        // reset to default (0 means the admin is not participating, so default should be returned)
+        dpm.setRequiredStrongAuthTimeout(admin1, 0);
 
         // aggregation should be the default if unset by any admin
         assertEquals(dpm.getRequiredStrongAuthTimeout(null),
@@ -2142,7 +2166,7 @@
         assertEquals(dpm.getRequiredStrongAuthTimeout(null),
                 DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
 
-        // 0 means default
+        // 0 means the admin is not participating, so default should be returned
         dpm.setRequiredStrongAuthTimeout(admin1, 0);
         assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
         assertEquals(dpm.getRequiredStrongAuthTimeout(null),
@@ -2153,12 +2177,14 @@
         assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
         assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
 
-        // value within range
-        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS
-                + ONE_MINUTE);
-        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS
-                + ONE_MINUTE);
+        // values within range
+        dpm.setRequiredStrongAuthTimeout(admin1, MIN_PLUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MIN_PLUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MIN_PLUS_ONE_MINUTE);
+
+        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);
 
         // reset to default
         dpm.setRequiredStrongAuthTimeout(admin1, 0);
@@ -3207,6 +3233,48 @@
         }
     }
 
+    public void testGetPermissionGrantState() throws Exception {
+        final String permission = "some.permission";
+        final String app1 = "com.example.app1";
+        final String app2 = "com.example.app2";
+
+        when(mContext.ipackageManager.checkPermission(eq(permission), eq(app1), anyInt()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        doReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED).when(mContext.packageManager)
+                .getPermissionFlags(permission, app1, UserHandle.SYSTEM);
+        when(mContext.packageManager.getPermissionFlags(permission, app1,
+                UserHandle.of(DpmMockContext.CALLER_USER_HANDLE)))
+                .thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED);
+        when(mContext.ipackageManager.checkPermission(eq(permission), eq(app2), anyInt()))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        doReturn(0).when(mContext.packageManager).getPermissionFlags(permission, app2,
+                UserHandle.SYSTEM);
+        when(mContext.packageManager.getPermissionFlags(permission, app2,
+                UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(0);
+
+        // System can retrieve permission grant state.
+        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
+                dpm.getPermissionGrantState(null, app1, permission));
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
+                dpm.getPermissionGrantState(null, app2, permission));
+
+        // A regular app cannot retrieve permission grant state.
+        mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        try {
+            dpm.getPermissionGrantState(null, app1, permission);
+            fail("Didn't throw IllegalStateException");
+        } catch (IllegalStateException expected) {
+        }
+
+        // Profile owner can retrieve permission grant state.
+        setAsProfileOwner(admin1);
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
+                dpm.getPermissionGrantState(admin1, app1, permission));
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
+                dpm.getPermissionGrantState(admin1, app2, permission));
+    }
+
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
         when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                 userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 228b8e0..9835c88 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -566,6 +566,7 @@
     protected Map<String, PackageInfo> mInjectedPackages;
 
     protected Set<PackageWithUser> mUninstalledPackages;
+    protected Set<PackageWithUser> mEphemeralPackages;
     protected Set<String> mSystemPackages;
 
     protected PackageManager mMockPackageManager;
@@ -618,9 +619,16 @@
     protected static final UserInfo USER_INFO_11 =
             new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
 
+    /*
+     * Cheat: USER_P0 is a sub profile of USER_0, but it doesn't have the MANAGED_PROFILE flag set.
+     * Due to a change made to LauncherApps (b/34340531), work profile apps a no longer able
+     * to see the main profile, which would break tons of unit tests.  We avoid it by not setting
+     * MANAGED_PROFILE for P0.
+     * We cover this negative case in CTS. (i.e. CTS has tests to make sure maanged profile
+     * can't access main profile's shortcuts.)
+     */
     protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
-            new UserInfo(USER_P0, "userP0",
-                    UserInfo.FLAG_MANAGED_PROFILE), 0);
+            new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0);
 
     protected BiPredicate<String, Integer> mDefaultLauncherChecker =
             (callingPackage, userId) ->
@@ -724,6 +732,7 @@
 
         mUninstalledPackages = new HashSet<>();
         mSystemPackages = new HashSet<>();
+        mEphemeralPackages = new HashSet<>();
 
         mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
 
@@ -1027,6 +1036,9 @@
         if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
             ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
         }
+        if (mEphemeralPackages.contains(PackageWithUser.of(userId, packageName))) {
+            ret.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
+        }
         if (mSystemPackages.contains(packageName)) {
             ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
index 5ab9020..b5a6178 100644
--- a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
@@ -80,11 +80,19 @@
     }
 
     public void testGetAppSize() throws Exception {
+        int[] appIds = null;
+
         final PackageManager pm = getContext().getPackageManager();
         for (ApplicationInfo app : pm.getInstalledApplications(0)) {
             final int userId = UserHandle.getUserId(app.uid);
             final int appId = UserHandle.getAppId(app.uid);
 
+            if (ArrayUtils.contains(appIds, appId)) {
+                continue;
+            } else {
+                appIds = ArrayUtils.appendInt(appIds, appId);
+            }
+
             final String[] packageNames = pm.getPackagesForUid(app.uid);
             final long[] ceDataInodes = new long[packageNames.length];
             final String[] codePaths = new String[packageNames.length];
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 64c5622..fec3267 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -39,7 +39,8 @@
     public PackageSetting generateFakePackageSetting(String name) {
         return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
                 new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
-                "", 1, 0, 0, null, null, 0 /*sharedUserId*/);
+                "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
index 5c552a2..e6b4540f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
@@ -20,7 +20,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
-import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.GlobalPresubmit;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -63,7 +63,7 @@
      */
     @Test
     @SmallTest
-    @Presubmit
+    @GlobalPresubmit
     public void testPrivAppPermissions() throws PackageManager.NameNotFoundException {
         List<PackageInfo> installedPackages = mPackageManager
                 .getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS);
@@ -103,12 +103,10 @@
                 // if privapp permissions are enforced, platform permissions must be whitelisted
                 // in SystemConfig
                 if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
-                    assertTrue("Permission " + pName
-                                    + " should be declared in "
-                                    + "/etc/permissions/privapp-permissions-platform.xml "
-                                    + "or privapp-permissions-<device>.xml file for package "
+                    assertTrue("Permission " + pName + " should be declared in "
+                                    + "privapp-permissions-<category>.xml file for package "
                                     + packageName,
-                            privAppPermissions.contains(pName));
+                            privAppPermissions != null && privAppPermissions.contains(pName));
                 }
                 assertTrue("Permission " + pName + " should be granted to " + packageName, granted);
             }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index bd2bb6c..baf60c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -216,7 +216,9 @@
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
                 PARENT_PACKAGE_NAME,
                 childPackageNames,
-                0);
+                0,
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         final PackageSetting testPkgSetting01 = new PackageSetting(origPkgSetting01);
         verifySettingCopy(origPkgSetting01, testPkgSetting01);
     }
@@ -241,7 +243,9 @@
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN,
                 PARENT_PACKAGE_NAME,
                 childPackageNames,
-                0);
+                0,
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         final PackageSetting testPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME /*pkgName*/,
                 REAL_PACKAGE_NAME /*realPkgName*/,
@@ -256,7 +260,9 @@
                 0 /*pkgPrivateFlags*/,
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
-                0);
+                0,
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         testPkgSetting01.copyFrom(origPkgSetting01);
         verifySettingCopy(origPkgSetting01, testPkgSetting01);
     }
@@ -281,7 +287,9 @@
                 0 /*pkgFlags*/,
                 0 /*pkgPrivateFlags*/,
                 null /*childPkgNames*/,
-                UserManagerService.getInstance());
+                UserManagerService.getInstance(),
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
         assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
         assertThat(testPkgSetting01.origPackage, is(nullValue()));
@@ -313,7 +321,9 @@
                 ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/,
                 ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/,
                 null /*childPkgNames*/,
-                UserManagerService.getInstance());
+                UserManagerService.getInstance(),
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
         assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
         assertThat(testPkgSetting01.origPackage, is(nullValue()));
@@ -348,7 +358,9 @@
                     0 /*pkgFlags*/,
                     0 /*pkgPrivateFlags*/,
                     null /*childPkgNames*/,
-                    UserManagerService.getInstance());
+                    UserManagerService.getInstance(),
+                    null /*usesStaticLibraries*/,
+                    null /*usesStaticLibrariesVersions*/);
             fail("Expected a PackageManagerException");
         } catch (PackageManagerException expected) {
         }
@@ -378,7 +390,9 @@
                 false /*allowInstall*/,
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
-                UserManagerService.getInstance());
+                UserManagerService.getInstance(),
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM));
@@ -416,7 +430,9 @@
                 true /*allowInstall*/,
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
-                UserManagerService.getInstance());
+                UserManagerService.getInstance(),
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         assertThat(testPkgSetting01.appId, is(0));
         assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
@@ -457,7 +473,9 @@
                 false /*allowInstall*/,
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
-                UserManagerService.getInstance());
+                UserManagerService.getInstance(),
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         assertThat(testPkgSetting01.appId, is(10064));
         assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
@@ -498,7 +516,9 @@
                 false /*allowInstall*/,
                 null /*parentPkgName*/,
                 null /*childPkgNames*/,
-                UserManagerService.getInstance());
+                UserManagerService.getInstance(),
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
         assertThat(testPkgSetting01.appId, is(10064));
         assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
@@ -624,7 +644,9 @@
                 0 /*privateFlags*/,
                 null /*parentPackageName*/,
                 null /*childPackageNames*/,
-                sharedUserId);
+                sharedUserId,
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
     }
 
     private @NonNull List<UserInfo> createFakeUsers() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
new file mode 100644
index 0000000..ca1e6af
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
@@ -0,0 +1,183 @@
+/*
+ * 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 static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
+        .assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.os.Process;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Tests for {@link ShortcutManager#createShortcutResultIntent(ShortcutInfo)} and relevant APIs.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest10 \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+public class ShortcutManagerTest10 extends BaseShortcutManagerTest {
+
+    private PinItemRequest mRequest;
+
+    private PinItemRequest verifyAndGetCreateShortcutResult(Intent resultIntent) {
+        PinItemRequest request = mLauncherApps.getPinItemRequest(resultIntent);
+        assertNotNull(request);
+        assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType());
+        return request;
+    }
+
+    public void testCreateShortcutResult_noDefaultLauncher() {
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertNull(mManager.createShortcutResultIntent(s1));
+        });
+    }
+
+    public void testCreateShortcutResult_validResult() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    public void testCreateShortcutResult_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertTrue(mRequest.getShortcutInfo().isPinned());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    public void testCreateShortcutResult_alreadyPinnedByAnother() {
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        // Initially all launchers have the shortcut permission, until we call setDefaultLauncher().
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertFalse(mRequest.getShortcutInfo().isPinned());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    public void testCreateShortcutResult_defaultLauncherChanges() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0));
+        // Verify that other launcher can't use this request
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertFalse(mRequest.isValid());
+            assertExpectException(SecurityException.class, "Calling uid mismatch",
+                    mRequest::accept);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Set some random caller UID.
+            mInjectedCallingUid = 12345;
+
+            assertFalse(mRequest.isValid());
+            assertExpectException(SecurityException.class, "Calling uid mismatch",
+                    mRequest::accept);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    private LauncherActivityInfo setupMockActivityInfo() {
+        doReturn(getTestContext().getPackageName()).when(mServiceContext).getPackageName();
+        doReturn(getTestContext().getContentResolver()).when(mServiceContext).getContentResolver();
+
+        LauncherActivityInfo info = mock(LauncherActivityInfo.class);
+        when(info.getComponentName()).thenReturn(
+                new ComponentName(getTestContext(), "a.ShortcutConfigActivity"));
+        when(info.getUser()).thenReturn(Process.myUserHandle());
+        return info;
+    }
+
+    public void testStartConfigActivity_defaultLauncher() {
+        LauncherActivityInfo info = setupMockActivityInfo();
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(LAUNCHER_1, USER_0, () ->
+            assertNotNull(mLauncherApps.getShortcutConfigActivityIntent(info))
+        );
+    }
+
+    public void testStartConfigActivity_nonDefaultLauncher() {
+        LauncherActivityInfo info = setupMockActivityInfo();
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(LAUNCHER_2, USER_0, () ->
+            assertExpectException(SecurityException.class, null, () ->
+                    mLauncherApps.getShortcutConfigActivityIntent(info))
+        );
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index d25923c..562de414 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -46,6 +46,7 @@
 
 import com.android.frameworks.servicestests.R;
 import com.android.server.pm.ShortcutService.ConfigConstants;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
 
 import java.io.File;
 import java.io.FileWriter;
@@ -2037,4 +2038,32 @@
         assertFalse(mService.isUserUnlockedL(USER_0));
         assertFalse(mService.isUserUnlockedL(USER_10));
     }
+
+    public void testEphemeralApp() {
+        mRunningUsers.put(USER_10, true); // this test needs user 10.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(mManager.getDynamicShortcuts()).isEmpty();
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertWith(mManager.getDynamicShortcuts()).isEmpty();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(mManager.getDynamicShortcuts()).isEmpty();
+        });
+        // Make package 1 ephemeral.
+        mEphemeralPackages.add(PackageWithUser.of(USER_0, CALLING_PACKAGE_1));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertExpectException(IllegalStateException.class, "Ephemeral apps", () -> {
+                mManager.getDynamicShortcuts();
+            });
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertWith(mManager.getDynamicShortcuts()).isEmpty();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertWith(mManager.getDynamicShortcuts()).isEmpty();
+        });
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index bcd72fc..96e8948 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -22,6 +22,9 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Matchers.notNull;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -238,7 +241,7 @@
      * - Launcher supports the feature.
      * - Shortcut doesn't pre-exist.
      */
-    private void checkRequestPinShortcut(@Nullable PendingIntent resultIntent) {
+    private void checkRequestPinShortcut(@Nullable IntentSender resultIntent) {
         setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
         setDefaultLauncher(USER_10, mMainActivityFetcher.apply(LAUNCHER_2, USER_10));
 
@@ -254,8 +257,7 @@
 
             assertNull(s.getActivity());
 
-            assertTrue(mManager.requestPinShortcut(s,
-                    resultIntent == null ? null : resultIntent.getIntentSender()));
+            assertTrue(mManager.requestPinShortcut(s, resultIntent));
 
             verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
 
@@ -294,9 +296,9 @@
 
         // This method is always called, even with PI == null.
         if (resultIntent == null) {
-            verify(mServiceContext, times(1)).sendIntentSender(eq(null));
+            verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class));
         } else {
-            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+            verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class));
         }
 
         runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
@@ -314,11 +316,12 @@
         checkRequestPinShortcut(/* resultIntent=*/ null);
     }
 
-    public void testRequestPinShortcut_withCallback() {
-        final PendingIntent resultIntent =
-                PendingIntent.getActivity(getTestContext(), 0, new Intent(), 0);
+    private IntentSender makeResultIntent() {
+        return PendingIntent.getActivity(getTestContext(), 0, new Intent(), 0).getIntentSender();
+    }
 
-        checkRequestPinShortcut(resultIntent);
+    public void testRequestPinShortcut_withCallback() {
+        checkRequestPinShortcut(makeResultIntent());
     }
 
     public void testRequestPinShortcut_explicitTargetActivity() {
@@ -578,8 +581,15 @@
     public void testRequestPinShortcut_dynamicExists_alreadyPinned() {
         setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
 
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+
         runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
-            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+            final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext, "s1")
+                    .setShortLabel("Title-" + "s1")
+                    .setIcon(res32x32)
+                    .setIntent(makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class));
+            final ShortcutInfo s = b.build();
+            assertTrue(mManager.setDynamicShortcuts(list(s)));
         });
 
         runWithCaller(LAUNCHER_1, USER_0, () -> {
@@ -590,14 +600,66 @@
             assertWith(getCallerShortcuts())
                     .haveIds("s1")
                     .areAllDynamic()
-                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "main"))
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "MainActivity"))
                     .areAllPinned();
 
             assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("s1"),
-                    /* resultIntent=*/ null));
+                    makeResultIntent()));
 
             // The intent should be sent right away.
-            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+            verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class));
+        });
+
+        // Already pinned.
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "MainActivity"))
+                    .areAllPinned();
+        });
+
+        // ... But the launcher will still receive the request.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllPinned() // Note it's pinned already.
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "MainActivity"))
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            reset(mServiceContext);
+
+            // Accept the request.
+            assertTrue(request.accept());
+
+            // The intent is only sent once, so times(1).
+            verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class));
+        });
+
+        // Still pinned.
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("s1")
+                    .areAllDynamic()
+                    .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1, "MainActivity"))
+                    .areAllPinned();
         });
     }
 
@@ -621,10 +683,65 @@
                     .areAllPinned();
 
             assertTrue(mManager.requestPinShortcut(makeShortcutIdOnly("ms1"),
-                    /* resultIntent=*/ null));
+                    makeResultIntent()));
 
             // The intent should be sent right away.
-            verify(mServiceContext, times(1)).sendIntentSender(any(IntentSender.class));
+            verify(mServiceContext, times(1)).sendIntentSender(notNull(IntentSender.class));
+        });
+
+        // Already pinned.
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
+                    .areAllPinned();
+        });
+
+        // ... But the launcher will still receive the request.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Check the intent passed to startActivityAsUser().
+            final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+
+            verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+
+            assertPinItemRequestIntent(intent.getValue(), mInjectedClientPackage);
+
+            // Check the request object.
+            final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+            assertPinItemRequest(request);
+
+            assertWith(request.getShortcutInfo())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllPinned() // Note it's pinned already.
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
+                    .areAllWithNoIntent();
+
+            assertAllHaveIcon(list(request.getShortcutInfo()));
+
+            reset(mServiceContext);
+
+            // Accept the request.
+            assertTrue(request.accept());
+
+            // The intent is only sent once, so times(1).
+            verify(mServiceContext, times(1)).sendIntentSender(isNull(IntentSender.class));
+        });
+
+        // Still pinned.
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertWith(getCallerShortcuts())
+                    .haveIds("ms1")
+                    .areAllManifest()
+                    .areAllEnabled()
+                    .areAllWithActivity(new ComponentName(CALLING_PACKAGE_1,
+                            ShortcutActivity.class.getName()))
+                    .areAllPinned();
         });
     }
 
@@ -1421,6 +1538,35 @@
         });
     }
 
+    public void testRequestPinShortcut_wrongLauncherCannotAccept() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertTrue(mManager.requestPinShortcut(s1, null));
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+        verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+        final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+        // Verify that other launcher can't use this request
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Set some random caller UID.
+            mInjectedCallingUid = 12345;
+
+            assertFalse(request.isValid());
+            assertExpectException(SecurityException.class, "Calling uid mismatch", request::accept);
+        });
+
+        // The default launcher can still use this request
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(request.isValid());
+            assertTrue(request.accept());
+        });
+    }
+
     // TODO More tests:
 
     // Cancel previous pending request and release memory?
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
index 84a7c19..cfa35c2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest9.java
@@ -83,7 +83,8 @@
     private void assertPinItemRequest(PinItemRequest actualRequest, String className) {
         assertNotNull(actualRequest);
         assertEquals(PinItemRequest.REQUEST_TYPE_APPWIDGET, actualRequest.getRequestType());
-        assertEquals(className, actualRequest.getAppWidgetProviderInfo().provider.getClassName());
+        assertEquals(className, actualRequest.getAppWidgetProviderInfo(getTestContext())
+                .provider.getClassName());
     }
 
     public void testNotForeground() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 11f9ebb..480be2e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -16,13 +16,16 @@
 
 package com.android.server.pm;
 
+import static com.android.server.devicepolicy.DpmTestUtils.assertRestrictions;
+import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions;
+
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.devicepolicy.DpmTestUtils;
+import android.util.SparseArray;
 
 /**
  * Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
@@ -49,14 +52,14 @@
     public void testIsEmpty() {
         assertTrue(UserRestrictionsUtils.isEmpty(null));
         assertTrue(UserRestrictionsUtils.isEmpty(new Bundle()));
-        assertFalse(UserRestrictionsUtils.isEmpty(DpmTestUtils.newRestrictions("a")));
+        assertFalse(UserRestrictionsUtils.isEmpty(newRestrictions("a")));
     }
 
     public void testClone() {
         Bundle in = new Bundle();
         Bundle out = UserRestrictionsUtils.clone(in);
         assertNotSame(in, out);
-        DpmTestUtils.assertRestrictions(out, new Bundle());
+        assertRestrictions(out, new Bundle());
 
         out = UserRestrictionsUtils.clone(null);
         assertNotNull(out);
@@ -64,16 +67,16 @@
     }
 
     public void testMerge() {
-        Bundle a = DpmTestUtils.newRestrictions("a", "d");
-        Bundle b = DpmTestUtils.newRestrictions("b", "d", "e");
+        Bundle a = newRestrictions("a", "d");
+        Bundle b = newRestrictions("b", "d", "e");
 
         UserRestrictionsUtils.merge(a, b);
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+        assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
 
         UserRestrictionsUtils.merge(a, null);
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+        assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
 
         try {
             UserRestrictionsUtils.merge(a, a);
@@ -114,25 +117,32 @@
         final Bundle local = new Bundle();
         final Bundle global = new Bundle();
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(null, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(null, false /* isDeviceOwner */,
+                UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
         assertEquals(0, global.size());
         assertEquals(0, local.size());
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false /* isDeviceOwner */,
+                UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
         assertEquals(0, global.size());
         assertEquals(0, local.size());
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(DpmTestUtils.newRestrictions(
+        // Restrictions set by DO.
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
                 UserManager.DISALLOW_ADJUST_VOLUME,
                 UserManager.DISALLOW_UNMUTE_MICROPHONE,
                 UserManager.DISALLOW_USB_FILE_TRANSFER,
                 UserManager.DISALLOW_CONFIG_TETHERING,
                 UserManager.DISALLOW_OUTGOING_BEAM,
-                UserManager.DISALLOW_APPS_CONTROL
-        ), global, local);
+                UserManager.DISALLOW_APPS_CONTROL,
+                UserManager.ENSURE_VERIFY_APPS
+        ), true /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
 
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+        assertRestrictions(newRestrictions(
+                // This one is global no matter who sets it.
+                UserManager.ENSURE_VERIFY_APPS,
+
                 // These can be set by PO too, but when DO sets them, they're global.
                 UserManager.DISALLOW_ADJUST_VOLUME,
                 UserManager.DISALLOW_UNMUTE_MICROPHONE,
@@ -142,11 +152,117 @@
                 UserManager.DISALLOW_CONFIG_TETHERING
         ), global);
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+        assertRestrictions(newRestrictions(
                 // They can be set by both DO/PO.
                 UserManager.DISALLOW_OUTGOING_BEAM,
                 UserManager.DISALLOW_APPS_CONTROL
         ), local);
+
+        local.clear();
+        global.clear();
+
+        // Restrictions set by PO.
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
+                UserManager.DISALLOW_ADJUST_VOLUME,
+                UserManager.DISALLOW_UNMUTE_MICROPHONE,
+                UserManager.DISALLOW_USB_FILE_TRANSFER,
+                UserManager.DISALLOW_CONFIG_TETHERING,
+                UserManager.DISALLOW_OUTGOING_BEAM,
+                UserManager.DISALLOW_APPS_CONTROL,
+                UserManager.ENSURE_VERIFY_APPS
+        ), false /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+
+        assertRestrictions(newRestrictions(
+                // This one is global no matter who sets it.
+                UserManager.ENSURE_VERIFY_APPS
+        ), global);
+
+        assertRestrictions(newRestrictions(
+                // These can be set by PO too, but when PO sets them, they're local.
+                UserManager.DISALLOW_ADJUST_VOLUME,
+                UserManager.DISALLOW_UNMUTE_MICROPHONE,
+
+                // They can be set by both DO/PO.
+                UserManager.DISALLOW_OUTGOING_BEAM,
+                UserManager.DISALLOW_APPS_CONTROL,
+
+                // These can only be set by DO.
+                UserManager.DISALLOW_USB_FILE_TRANSFER,
+                UserManager.DISALLOW_CONFIG_TETHERING
+        ), local);
+
+    }
+
+    public void testSortToLocalAndGlobalWithCameraDisabled() {
+        final Bundle local = new Bundle();
+        final Bundle global = new Bundle();
+
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+                UserManagerInternal.CAMERA_DISABLED_GLOBALLY, global, local);
+        assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
+        assertEquals(0, local.size());
+        global.clear();
+
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+                UserManagerInternal.CAMERA_DISABLED_LOCALLY, global, local);
+        assertEquals(0, global.size());
+        assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
+    }
+
+    public void testMergeAll() {
+        SparseArray<Bundle> restrictions = new SparseArray<>();
+        assertNull(UserRestrictionsUtils.mergeAll(restrictions));
+
+        restrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME));
+        restrictions.put(1, newRestrictions(UserManager.DISALLOW_USB_FILE_TRANSFER));
+        restrictions.put(2, newRestrictions(UserManager.DISALLOW_APPS_CONTROL));
+
+        Bundle result = UserRestrictionsUtils.mergeAll(restrictions);
+        assertRestrictions(
+                newRestrictions(
+                        UserManager.DISALLOW_ADJUST_VOLUME,
+                        UserManager.DISALLOW_USB_FILE_TRANSFER,
+                        UserManager.DISALLOW_APPS_CONTROL),
+                result);
+    }
+
+    public void testMoveRestriction() {
+        SparseArray<Bundle> localRestrictions = new SparseArray<>();
+        SparseArray<Bundle> globalRestrictions = new SparseArray<>();
+
+        // User 0 has only local restrictions, nothing should change.
+        localRestrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME));
+        // User 1 has a local restriction to be moved to global and some global already. Local
+        // restrictions should be removed for this user.
+        localRestrictions.put(1, newRestrictions(UserManager.ENSURE_VERIFY_APPS));
+        globalRestrictions.put(1, newRestrictions(UserManager.DISALLOW_ADD_USER));
+        // User 2 has a local restriction to be moved and one to leave local.
+        localRestrictions.put(2, newRestrictions(
+                UserManager.ENSURE_VERIFY_APPS,
+                UserManager.DISALLOW_CONFIG_VPN));
+
+        UserRestrictionsUtils.moveRestriction(
+                UserManager.ENSURE_VERIFY_APPS, localRestrictions, globalRestrictions);
+
+        // Check user 0.
+        assertRestrictions(
+                newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME),
+                localRestrictions.get(0));
+        assertNull(globalRestrictions.get(0));
+
+        // Check user 1.
+        assertNull(localRestrictions.get(1));
+        assertRestrictions(
+                newRestrictions(UserManager.ENSURE_VERIFY_APPS, UserManager.DISALLOW_ADD_USER),
+                globalRestrictions.get(1));
+
+        // Check user 2.
+        assertRestrictions(
+                newRestrictions(UserManager.DISALLOW_CONFIG_VPN),
+                localRestrictions.get(2));
+        assertRestrictions(
+                newRestrictions(UserManager.ENSURE_VERIFY_APPS),
+                globalRestrictions.get(2));
     }
 
     public void testAreEqual() {
@@ -172,33 +288,33 @@
 
         assertFalse(UserRestrictionsUtils.areEqual(
                 null,
-                DpmTestUtils.newRestrictions("a")));
+                newRestrictions("a")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a"),
+                newRestrictions("a"),
                 null));
 
         assertTrue(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a"),
-                DpmTestUtils.newRestrictions("a")));
+                newRestrictions("a"),
+                newRestrictions("a")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a"),
-                DpmTestUtils.newRestrictions("a", "b")));
+                newRestrictions("a"),
+                newRestrictions("a", "b")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a", "b"),
-                DpmTestUtils.newRestrictions("a")));
+                newRestrictions("a", "b"),
+                newRestrictions("a")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("b", "a"),
-                DpmTestUtils.newRestrictions("a", "a")));
+                newRestrictions("b", "a"),
+                newRestrictions("a", "a")));
 
         // Make sure false restrictions are handled correctly.
-        final Bundle a = DpmTestUtils.newRestrictions("a");
+        final Bundle a = newRestrictions("a");
         a.putBoolean("b", true);
 
-        final Bundle b = DpmTestUtils.newRestrictions("a");
+        final Bundle b = newRestrictions("a");
         b.putBoolean("b", false);
 
         assertFalse(UserRestrictionsUtils.areEqual(a, b));
diff --git a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
new file mode 100644
index 0000000..e2aff16
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
@@ -0,0 +1,268 @@
+/*
+ * 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.server.policy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.test.runner.AndroidJUnit4;
+
+import android.test.mock.MockContentResolver;
+import android.text.TextUtils;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+import android.widget.Toast;
+import com.android.internal.R;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.policy.AccessibilityShortcutController.FrameworkObjectProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.Whitebox;
+
+import java.util.Collections;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityShortcutControllerTest {
+    private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
+
+    private @Mock Context mContext;
+    private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
+    private @Mock IAccessibilityManager mAccessibilityManagerService;
+    private @Mock Handler mHandler;
+    private @Mock AlertDialog.Builder mAlertDialogBuilder;
+    private @Mock AlertDialog mAlertDialog;
+    private @Mock AccessibilityServiceInfo mServiceInfo;
+    private @Mock Resources mResources;
+    private @Mock Toast mToast;
+
+    private MockContentResolver mContentResolver;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContentResolver = new MockContentResolver(mContext);
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mResources);
+
+        when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt()))
+                .thenReturn(Collections.singletonList(mServiceInfo));
+
+        // Use the extra level of indirection in the object to mock framework objects
+        AccessibilityManager accessibilityManager =
+                new AccessibilityManager(mHandler, mAccessibilityManagerService, 0);
+        when(mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext))
+                .thenReturn(accessibilityManager);
+        when(mFrameworkObjectProvider.getAlertDialogBuilder(mContext))
+                .thenReturn(mAlertDialogBuilder);
+        when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt()))
+                .thenReturn(mToast);
+
+        when(mResources.getString(anyInt())).thenReturn("Howdy %s");
+        ResolveInfo resolveInfo = mock(ResolveInfo.class);
+        when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name");
+        when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
+        when(mServiceInfo.getComponentName())
+                .thenReturn(ComponentName.unflattenFromString(SERVICE_NAME_STRING));
+
+        when(mAlertDialogBuilder.setTitle(anyInt())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setCancelable(anyBoolean())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setMessage(anyObject())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setPositiveButton(anyInt(), anyObject()))
+                .thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setNegativeButton(anyInt(), anyObject()))
+                .thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setOnCancelListener(anyObject())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.create()).thenReturn(mAlertDialog);
+
+        Window window = mock(Window.class);
+        Whitebox.setInternalState(window, "mWindowAttributes", new WindowManager.LayoutParams());
+        when(mAlertDialog.getWindow()).thenReturn(window);
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void testShortcutAvailable_withNullServiceIdWhenCreated_shouldReturnFalse() {
+        configureShortcutDisabled();
+        assertFalse(getController().isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testShortcutAvailable_withNonNullServiceIdWhenCreated_shouldReturnTrue() {
+        configureShortcutEnabled();
+        assertTrue(getController().isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
+        accessibilityShortcutController.onSettingsChanged();
+        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue() {
+        configureShortcutDisabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        configureShortcutEnabled();
+        accessibilityShortcutController.onSettingsChanged();
+        assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_firstTime_showsWarningDialog()
+            throws Exception {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+
+        assertEquals(1, Settings.Secure.getInt(
+                mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0));
+        verify(mResources).getString(R.string.accessibility_shortcut_toogle_warning);
+        verify(mAlertDialog).show();
+        verify(mAccessibilityManagerService).getInstalledAccessibilityServiceList(anyInt());
+        verify(mAccessibilityManagerService, times(0)).performAccessibilityShortcut();
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_withDialogShowing_callsServer()
+        throws Exception {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+        accessibilityShortcutController.performAccessibilityShortcut();
+        verify(mToast).show();
+        verify(mAccessibilityManagerService, times(1)).performAccessibilityShortcut();
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_ifCanceledFirstTime_showsWarningDialog()
+        throws Exception {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+        ArgumentCaptor<AlertDialog.OnCancelListener> cancelListenerCaptor =
+                ArgumentCaptor.forClass(AlertDialog.OnCancelListener.class);
+        verify(mAlertDialogBuilder).setOnCancelListener(cancelListenerCaptor.capture());
+        // Call the cancel callback
+        cancelListenerCaptor.getValue().onCancel(null);
+
+        accessibilityShortcutController.performAccessibilityShortcut();
+        verify(mAlertDialog, times(2)).show();
+    }
+
+    @Test
+    public void testClickingDisableButtonInDialog_shouldClearShortcutId() {
+        configureShortcutEnabled();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        getController().performAccessibilityShortcut();
+
+        ArgumentCaptor<DialogInterface.OnClickListener> captor =
+                ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+        verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.disable_accessibility_shortcut),
+                captor.capture());
+        // Call the button callback
+        captor.getValue().onClick(null, 0);
+        assertTrue(TextUtils.isEmpty(
+                Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)));
+    }
+
+    @Test
+    public void testClickingLeaveOnButtonInDialog_shouldLeaveShortcutReady() throws Exception {
+        configureShortcutEnabled();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        getController().performAccessibilityShortcut();
+
+        ArgumentCaptor<DialogInterface.OnClickListener> captor =
+            ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+        verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.leave_accessibility_shortcut_on),
+            captor.capture());
+        // Call the button callback, if one exists
+        if (captor.getValue() != null) {
+            captor.getValue().onClick(null, 0);
+        }
+        assertEquals(SERVICE_NAME_STRING,
+                Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
+        assertEquals(1, Settings.Secure.getInt(
+            mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_afterDialogShown_shouldCallServer() throws Exception {
+        configureShortcutEnabled();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+        getController().performAccessibilityShortcut();
+
+        verifyZeroInteractions(mAlertDialogBuilder, mAlertDialog);
+        verify(mToast).show();
+        verify(mAccessibilityManagerService).performAccessibilityShortcut();
+    }
+
+    private void configureShortcutDisabled() {
+        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
+    }
+
+    private void configureShortcutEnabled() {
+        Settings.Secure.putString(
+                mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
+    }
+
+    private AccessibilityShortcutController getController() {
+        AccessibilityShortcutController accessibilityShortcutController =
+                new AccessibilityShortcutController(mContext, mHandler);
+        accessibilityShortcutController.mFrameworkObjectProvider = mFrameworkObjectProvider;
+        return accessibilityShortcutController;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index d2512ac..67e78d4 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -19,18 +19,27 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.database.ContentObserver;
+import android.content.pm.UserInfo;
+import android.webkit.UserPackage;
 import android.webkit.WebViewProviderInfo;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public class TestSystemImpl implements SystemInterface {
     private String mUserProvider = null;
     private final WebViewProviderInfo[] mPackageConfigs;
-    HashMap<String, PackageInfo> mPackages = new HashMap();
+    List<Integer> mUsers = new ArrayList<>();
+    // Package -> [user, package]
+    Map<String, Map<Integer, PackageInfo>> mPackages = new HashMap();
     private boolean mFallbackLogicEnabled;
     private final int mNumRelros;
     private final boolean mIsDebuggable;
+    private int mMultiProcessSetting;
+
+    public static final int PRIMARY_USER_ID = 0;
 
     public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled,
             int numRelros, boolean isDebuggable) {
@@ -38,6 +47,11 @@
         mFallbackLogicEnabled = fallbackLogicEnabled;
         mNumRelros = numRelros;
         mIsDebuggable = isDebuggable;
+        mUsers.add(PRIMARY_USER_ID);
+    }
+
+    public void addUser(int userId) {
+        mUsers.add(userId);
     }
 
     @Override
@@ -78,17 +92,20 @@
 
     @Override
     public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
-        enablePackageForUser(packageName, enable, 0);
+        for(int userId : mUsers) {
+            enablePackageForUser(packageName, enable, userId);
+        }
     }
 
     @Override
     public void enablePackageForUser(String packageName, boolean enable, int userId) {
-        PackageInfo packageInfo = mPackages.get(packageName);
-        if (packageInfo == null) {
+        Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
+        if (userPackages == null) {
             throw new IllegalArgumentException("There is no package called " + packageName);
         }
+        PackageInfo packageInfo = userPackages.get(userId);
         packageInfo.applicationInfo.enabled = enable;
-        setPackageInfo(packageInfo);
+        setPackageInfoForUser(userId, packageInfo);
     }
 
     @Override
@@ -97,23 +114,61 @@
     @Override
     public PackageInfo getPackageInfoForProvider(WebViewProviderInfo info) throws
             NameNotFoundException {
-        PackageInfo ret = mPackages.get(info.packageName);
+        Map<Integer, PackageInfo> userPackages = mPackages.get(info.packageName);
+        if (userPackages == null) throw new NameNotFoundException(info.packageName);
+        PackageInfo ret = userPackages.get(PRIMARY_USER_ID);
         if (ret == null) throw new NameNotFoundException(info.packageName);
         return ret;
     }
 
-    public void setPackageInfo(PackageInfo pi) {
-        mPackages.put(pi.packageName, pi);
+    @Override
+    public List<UserPackage> getPackageInfoForProviderAllUsers(
+            Context context, WebViewProviderInfo info) {
+        Map<Integer, PackageInfo> userPackages = mPackages.get(info.packageName);
+        List<UserPackage> ret = new ArrayList();
+        // Loop over defined users, and find the corresponding package for each user.
+        for (int userId : mUsers) {
+            ret.add(new UserPackage(createUserInfo(userId),
+                    userPackages == null ? null : userPackages.get(userId)));
+        }
+        return ret;
     }
 
+    private static UserInfo createUserInfo(int userId) {
+        return new UserInfo(userId, "User nr. " + userId, 0 /* flags */);
+    }
+
+    /**
+     * Set package for primary user.
+     */
+    public void setPackageInfo(PackageInfo pi) {
+        setPackageInfoForUser(PRIMARY_USER_ID, pi);
+    }
+
+    public void setPackageInfoForUser(int userId, PackageInfo pi) {
+        if (!mUsers.contains(userId)) {
+            throw new IllegalArgumentException("User nr. " + userId + " doesn't exist");
+        }
+        if (!mPackages.containsKey(pi.packageName)) {
+            mPackages.put(pi.packageName, new HashMap<Integer, PackageInfo>());
+        }
+        mPackages.get(pi.packageName).put(userId, pi);
+    }
+
+    /**
+     * Removes the package {@param packageName} for the primary user.
+     */
     public void removePackageInfo(String packageName) {
-        mPackages.remove(packageName);
+        mPackages.get(packageName).remove(PRIMARY_USER_ID);
     }
 
     @Override
     public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
         PackageInfo pi = null;
-        pi = mPackages.get(packageName);
+        Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
+        if (userPackages == null) throw new NameNotFoundException();
+
+        pi = userPackages.get(PRIMARY_USER_ID);
         if (pi != null && pi.applicationInfo.isSystemApp()) {
             return pi.applicationInfo.versionCode;
         }
@@ -121,8 +176,15 @@
     }
 
     @Override
-    public void setMultiProcessEnabledFromContext(Context context) {}
+    public int getMultiProcessSetting(Context context) {
+        return mMultiProcessSetting;
+    }
 
     @Override
-    public void registerContentObserver(Context context, ContentObserver contentObserver) {}
+    public void setMultiProcessSetting(Context context, int value) {
+        mMultiProcessSetting = value;
+    }
+
+    @Override
+    public void notifyZygote(boolean enableMultiProcess) {}
 }
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 0519448..33cedfa 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -92,9 +92,15 @@
     }
 
     private void setEnabledAndValidPackageInfos(WebViewProviderInfo[] providers) {
+        // Set package infos for the primary user (user 0).
+        setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, providers);
+    }
+
+    private void setEnabledAndValidPackageInfosForUser(int userId,
+            WebViewProviderInfo[] providers) {
         for(WebViewProviderInfo wpi : providers) {
-            mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true /* enabled */,
-                        true /* valid */, true /* installed */));
+            mTestSystemImpl.setPackageInfoForUser(userId, createPackageInfo(wpi.packageName,
+                    true /* enabled */, true /* valid */, true /* installed */));
         }
     }
 
@@ -335,7 +341,7 @@
         setEnabledAndValidPackageInfos(packages);
 
         mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
-                WebViewUpdateService.PACKAGE_ADDED, 0);
+                WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
 
         checkPreparationPhasesForPackage(singlePackage, 1 /* number of finished preparations */);
         assertEquals(singlePackage,
@@ -344,7 +350,7 @@
         // Remove the package again
         mTestSystemImpl.removePackageInfo(singlePackage);
         mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
-                WebViewUpdateService.PACKAGE_ADDED, 0);
+                WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
 
         // Package removed - ensure our interface states that there is no package
         response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
@@ -374,7 +380,7 @@
                 createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */,
                     true /* installed */));
         mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
 
         checkPreparationPhasesForPackage(wpi.packageName, 1);
     }
@@ -429,16 +435,8 @@
             new WebViewProviderInfo(firstPackage, "", true, false, null),
             new WebViewProviderInfo(secondPackage, "", true, false, null)};
         setupWithPackages(packages);
-        if (settingsChange) {
-            // Have all packages be enabled, so that we can change provider however we want to
-            setEnabledAndValidPackageInfos(packages);
-        } else {
-            // Have all packages be disabled so that we can change one to enabled later
-            for(WebViewProviderInfo wpi : packages) {
-                mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName,
-                            false /* enabled */, true /* valid */, true /* installed */));
-            }
-        }
+        // Have all packages be enabled, so that we can change provider however we want to
+        setEnabledAndValidPackageInfos(packages);
 
         CountDownLatch countdown = new CountDownLatch(1);
 
@@ -457,8 +455,12 @@
                     mWebViewUpdateServiceImpl.waitForAndGetProvider();
                 assertEquals(WebViewFactory.LIBLOAD_SUCCESS, threadResponse.status);
                 assertEquals(secondPackage, threadResponse.packageInfo.packageName);
-                // Verify that we killed the first package
-                Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
+                // Verify that we killed the first package if we performed a settings change -
+                // otherwise we had to disable the first package, in which case its dependents
+                // should have been killed by the framework.
+                if (settingsChange) {
+                    Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
+                }
                 countdown.countDown();
             }
         }).start();
@@ -470,11 +472,21 @@
         if (settingsChange) {
             mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
         } else {
-            // Switch provider by enabling the second one
+            // Enable the second provider
             mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
                         true /* valid */, true /* installed */));
             mWebViewUpdateServiceImpl.packageStateChanged(
-                    secondPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
+                    secondPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID);
+
+            // Ensure we haven't changed package yet.
+            assertEquals(firstPackage,
+                    mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+
+            // Switch provider by disabling the first one
+            mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, false /* enabled */,
+                        true /* valid */, true /* installed */));
+            mWebViewUpdateServiceImpl.packageStateChanged(
+                    firstPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID);
         }
         mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
         // first package done, should start on second
@@ -528,7 +540,7 @@
         mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
                         true /* valid */, true /* installed */));
         mWebViewUpdateServiceImpl.packageStateChanged(
-                fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, 0);
+                fallbackPackage, WebViewUpdateService.PACKAGE_CHANGED, TestSystemImpl.PRIMARY_USER_ID);
 
         if (fallbackLogicEnabled) {
             // Check that we have now disabled the fallback package twice
@@ -573,7 +585,7 @@
                 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */,
                     true /* installed */));
         mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
 
         // Verify fallback disabled, primary package used as provider, and fallback package killed
         Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
@@ -583,7 +595,31 @@
     }
 
     @Test
-    public void testFallbackChangesEnabledState() {
+    public void testFallbackChangesEnabledStateSingleUser() {
+        for (PackageRemovalType removalType : REMOVAL_TYPES) {
+            checkFallbackChangesEnabledState(false /* multiUser */, removalType);
+        }
+    }
+
+    @Test
+    public void testFallbackChangesEnabledStateMultiUser() {
+        for (PackageRemovalType removalType : REMOVAL_TYPES) {
+            checkFallbackChangesEnabledState(true /* multiUser */, removalType);
+        }
+    }
+
+    /**
+     * Represents how to remove a package during a tests (disabling it / uninstalling it / hiding
+     * it).
+     */
+    private enum PackageRemovalType {
+        UNINSTALL, DISABLE, HIDE
+    }
+
+    private PackageRemovalType[] REMOVAL_TYPES = PackageRemovalType.class.getEnumConstants();
+
+    public void checkFallbackChangesEnabledState(boolean multiUser,
+            PackageRemovalType removalType) {
         String primaryPackage = "primary";
         String fallbackPackage = "fallback";
         WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
@@ -592,46 +628,68 @@
             new WebViewProviderInfo(
                     fallbackPackage, "", true /* default available */, true /* fallback */, null)};
         setupWithPackages(packages, true /* fallbackLogicEnabled */);
-        setEnabledAndValidPackageInfos(packages);
+        int secondaryUserId = 10;
+        int userIdToChangePackageFor = multiUser ? secondaryUserId : TestSystemImpl.PRIMARY_USER_ID;
+        if (multiUser) {
+            mTestSystemImpl.addUser(secondaryUserId);
+            setEnabledAndValidPackageInfosForUser(secondaryUserId, packages);
+        }
+        setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
 
         runWebViewBootPreparationOnMainSync();
 
         // Verify fallback disabled at boot when primary package enabled
-        Mockito.verify(mTestSystemImpl).enablePackageForUser(
-                Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
-                Matchers.anyInt());
+        checkEnablePackageForUserCalled(fallbackPackage, false, multiUser
+                ? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId}
+                : new int[] {TestSystemImpl.PRIMARY_USER_ID}, 1 /* numUsages */);
 
         checkPreparationPhasesForPackage(primaryPackage, 1);
 
+        boolean enabled = !(removalType == PackageRemovalType.DISABLE);
+        boolean installed = !(removalType == PackageRemovalType.UNINSTALL);
+        boolean hidden = (removalType == PackageRemovalType.HIDE);
         // Disable primary package and ensure fallback becomes enabled and used
-        mTestSystemImpl.setPackageInfo(
-                createPackageInfo(primaryPackage, false /* enabled */, true /* valid */,
-                    true /* installed */));
+        mTestSystemImpl.setPackageInfoForUser(userIdToChangePackageFor,
+                createPackageInfo(primaryPackage, enabled /* enabled */, true /* valid */,
+                    installed /* installed */, null /* signature */, 0 /* updateTime */,
+                    hidden /* hidden */));
         mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_CHANGED, 0);
+                removalType == PackageRemovalType.DISABLE
+                ? WebViewUpdateService.PACKAGE_CHANGED : WebViewUpdateService.PACKAGE_REMOVED,
+                userIdToChangePackageFor); // USER ID
 
-        Mockito.verify(mTestSystemImpl).enablePackageForUser(
-                Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
-                Matchers.anyInt());
+        checkEnablePackageForUserCalled(fallbackPackage, true, multiUser
+                ? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId}
+                : new int[] {TestSystemImpl.PRIMARY_USER_ID}, 1 /* numUsages */);
 
         checkPreparationPhasesForPackage(fallbackPackage, 1);
 
 
         // Again enable primary package and verify primary is used and fallback becomes disabled
-        mTestSystemImpl.setPackageInfo(
+        mTestSystemImpl.setPackageInfoForUser(userIdToChangePackageFor,
                 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
                     true /* installed */));
         mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_CHANGED, 0);
+                removalType == PackageRemovalType.DISABLE
+                ? WebViewUpdateService.PACKAGE_CHANGED : WebViewUpdateService.PACKAGE_ADDED,
+                userIdToChangePackageFor);
 
         // Verify fallback is disabled a second time when primary package becomes enabled
-        Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
-                Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
-                Matchers.anyInt());
+        checkEnablePackageForUserCalled(fallbackPackage, false, multiUser
+                ? new int[] {TestSystemImpl.PRIMARY_USER_ID, secondaryUserId}
+                : new int[] {TestSystemImpl.PRIMARY_USER_ID}, 2 /* numUsages */);
 
         checkPreparationPhasesForPackage(primaryPackage, 2);
     }
 
+    private void checkEnablePackageForUserCalled(String packageName, boolean expectEnabled,
+            int[] userIds, int numUsages) {
+        for (int userId : userIds) {
+            Mockito.verify(mTestSystemImpl, Mockito.times(numUsages)).enablePackageForUser(
+                    Mockito.eq(packageName), Mockito.eq(expectEnabled), Mockito.eq(userId));
+        }
+    }
+
     @Test
     public void testAddUserWhenFallbackLogicEnabled() {
         checkAddingNewUser(true);
@@ -651,8 +709,10 @@
             new WebViewProviderInfo(
                     fallbackPackage, "", true /* default available */, true /* fallback */, null)};
         setupWithPackages(packages, fallbackLogicEnabled);
-        setEnabledAndValidPackageInfos(packages);
+        setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
         int newUser = 100;
+        mTestSystemImpl.addUser(newUser);
+        setEnabledAndValidPackageInfosForUser(newUser, packages);
         mWebViewUpdateServiceImpl.handleNewUser(newUser);
         if (fallbackLogicEnabled) {
             // Verify fallback package becomes disabled for new user
@@ -668,6 +728,42 @@
     }
 
     /**
+     * Ensures that adding a new user for which the current WebView package is uninstalled causes a
+     * change of WebView provider.
+     */
+    @Test
+    public void testAddingNewUserWithUninstalledPackage() {
+        String primaryPackage = "primary";
+        String fallbackPackage = "fallback";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(
+                    primaryPackage, "", true /* default available */, false /* fallback */, null),
+            new WebViewProviderInfo(
+                    fallbackPackage, "", true /* default available */, true /* fallback */, null)};
+        setupWithPackages(packages, true /* fallbackLogicEnabled */);
+        setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
+        int newUser = 100;
+        mTestSystemImpl.addUser(newUser);
+        // Let the primary package be uninstalled for the new user
+        mTestSystemImpl.setPackageInfoForUser(newUser,
+                createPackageInfo(primaryPackage, true /* enabled */, true /* valid */,
+                        false /* installed */));
+        mTestSystemImpl.setPackageInfoForUser(newUser,
+                createPackageInfo(fallbackPackage, false /* enabled */, true /* valid */,
+                        true /* installed */));
+        mWebViewUpdateServiceImpl.handleNewUser(newUser);
+        // Verify fallback package doesn't become disabled for the primary user.
+        Mockito.verify(mTestSystemImpl, Mockito.never()).enablePackageForUser(
+                Mockito.anyObject(), Mockito.eq(false) /* enable */,
+                Mockito.eq(TestSystemImpl.PRIMARY_USER_ID) /* user */);
+        // Verify that we enable the fallback package for the secondary user.
+        Mockito.verify(mTestSystemImpl, Mockito.times(1)).enablePackageForUser(
+                Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
+                Mockito.eq(newUser) /* user */);
+        checkPreparationPhasesForPackage(fallbackPackage, 1 /* numRelros */);
+    }
+
+    /**
      * Timing dependent test where we verify that the list of valid webview packages becoming empty
      * at a certain point doesn't crash us or break our state.
      */
@@ -713,7 +809,7 @@
                     1 /* updateTime */ ));
 
         mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
 
         // Ensure we use firstPackage
         checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
@@ -742,14 +838,14 @@
         mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
                     false /* valid */, true /* installed */));
         mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
-                WebViewUpdateService.PACKAGE_ADDED, 0);
+                WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
         checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
 
         // Now make the second package valid again and verify that it is used again
         mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
                     true /* valid */, true /* installed */));
         mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
-                WebViewUpdateService.PACKAGE_ADDED, 0);
+                WebViewUpdateService.PACKAGE_ADDED, TestSystemImpl.PRIMARY_USER_ID);
         checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
     }
 
@@ -820,7 +916,7 @@
             mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
         } else {
             mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
-                    WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+                    WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
         }
 
         WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
@@ -831,7 +927,7 @@
                     true /* valid */, true /* installed */));
 
         mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
 
 
         checkPreparationPhasesForPackage(secondPackage, 1);
@@ -863,11 +959,11 @@
                     createPackageInfo(firstPackage, true /* enabled */, false /* valid */,
                         true /* installed */));
             mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
-                    WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
+                    WebViewUpdateService.PACKAGE_ADDED_REPLACED, TestSystemImpl.PRIMARY_USER_ID);
         } else {
             mTestSystemImpl.removePackageInfo(firstPackage);
             mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
-                    WebViewUpdateService.PACKAGE_REMOVED, 0);
+                    WebViewUpdateService.PACKAGE_REMOVED, TestSystemImpl.PRIMARY_USER_ID);
         }
 
         checkPreparationPhasesForPackage(secondPackage, 1);
@@ -1098,8 +1194,10 @@
         }
     }
 
-    // Ensure that the update service uses an uninstalled package if that is the only package
-    // available.
+    /**
+     * Ensure that the update service does use an uninstalled package when that is the only
+     * package available.
+     */
     @Test
     public void testWithSingleUninstalledPackage() {
         String testPackageName = "test.package.name";
@@ -1113,21 +1211,32 @@
         runWebViewBootPreparationOnMainSync();
 
         checkPreparationPhasesForPackage(testPackageName, 1 /* first preparation phase */);
+        // TODO(gsennton) change this logic to use the code below when we have created a functional
+        // stub.
+        //Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
+        //        Matchers.anyObject());
+        //WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+        //assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+        //assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
     }
 
     @Test
     public void testNonhiddenPackageUserOverHidden() {
-        checkVisiblePackageUserOverNonVisible(false /* true == uninstalled, false == hidden */);
+        checkVisiblePackageUserOverNonVisible(false /* multiUser*/, PackageRemovalType.HIDE);
+        checkVisiblePackageUserOverNonVisible(true /* multiUser*/, PackageRemovalType.HIDE);
     }
 
     @Test
     public void testInstalledPackageUsedOverUninstalled() {
-        checkVisiblePackageUserOverNonVisible(true /* true == uninstalled, false == hidden */);
+        checkVisiblePackageUserOverNonVisible(false /* multiUser*/, PackageRemovalType.UNINSTALL);
+        checkVisiblePackageUserOverNonVisible(true /* multiUser*/, PackageRemovalType.UNINSTALL);
     }
 
-    private void checkVisiblePackageUserOverNonVisible(boolean uninstalledNotHidden) {
-        boolean testUninstalled = uninstalledNotHidden;
-        boolean testHidden = !uninstalledNotHidden;
+    private void checkVisiblePackageUserOverNonVisible(boolean multiUser,
+            PackageRemovalType removalType) {
+        assert removalType != PackageRemovalType.DISABLE;
+        boolean testUninstalled = removalType == PackageRemovalType.UNINSTALL;
+        boolean testHidden = removalType == PackageRemovalType.HIDE;
         String installedPackage = "installedPackage";
         String uninstalledPackage = "uninstalledPackage";
         WebViewProviderInfo[] webviewPackages = new WebViewProviderInfo[] {
@@ -1137,11 +1246,25 @@
                     false /* fallback */, null)};
 
         setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
-        mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
-                    true /* valid */, true /* installed */));
-        mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
+        int secondaryUserId = 5;
+        if (multiUser) {
+            mTestSystemImpl.addUser(secondaryUserId);
+            // Install all packages for the primary user.
+            setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages);
+            mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(
+                    installedPackage, true /* enabled */, true /* valid */, true /* installed */));
+            // Hide or uninstall the primary package for the second user
+            mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
                     true /* valid */, (testUninstalled ? false : true) /* installed */,
                     null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
+        } else {
+            mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
+                    true /* valid */, true /* installed */));
+            // Hide or uninstall the primary package
+            mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
+                    true /* valid */, (testUninstalled ? false : true) /* installed */,
+                    null /* signatures */, 0 /* updateTime */, (testHidden ? true : false)));
+        }
 
         runWebViewBootPreparationOnMainSync();
 
@@ -1160,9 +1283,7 @@
     }
 
     /**
-     * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen,
-     * and that an uninstalled (or hidden) package is not considered valid (in the
-     * getValidWebViewPackages() API).
+     * Ensure that we won't prioritize an uninstalled (or hidden) package even if it is user-chosen.
      */
     private void checkCantSwitchToNonVisiblePackage(boolean uninstalledNotHidden) {
         boolean testUninstalled = uninstalledNotHidden;
@@ -1176,27 +1297,31 @@
                     false /* fallback */, null)};
 
         setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
-        mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
-                    true /* valid */, true /* installed */));
-        mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
-                    true /* valid */, (testUninstalled ? false : true) /* installed */,
-                    null /* signatures */, 0 /* updateTime */,
-                    (testHidden ? true : false) /* hidden */));
+        int secondaryUserId = 412;
+        mTestSystemImpl.addUser(secondaryUserId);
+
+        // Let all packages be installed and enabled for the primary user.
+        setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages);
+        // Only uninstall the 'uninstalled package' for the secondary user.
+        mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(installedPackage,
+                true /* enabled */, true /* valid */, true /* installed */));
+        mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(uninstalledPackage,
+                true /* enabled */, true /* valid */, !testUninstalled /* installed */,
+                null /* signatures */, 0 /* updateTime */, testHidden /* hidden */));
 
         runWebViewBootPreparationOnMainSync();
 
         checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
 
-        // Ensure that only the installed package is considered valid
-        WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
-        assertEquals(1, validPackages.length);
-        assertEquals(installedPackage, validPackages[0].packageName);
-
         // ensure that we don't switch to the uninstalled package (it will be used if it becomes
         // installed later)
         assertEquals(installedPackage,
                 mWebViewUpdateServiceImpl.changeProviderAndSetting(uninstalledPackage));
 
+        // Ensure both packages are considered valid.
+        assertEquals(2, mWebViewUpdateServiceImpl.getValidWebViewPackages().length);
+
+
         // We should only have called onWebViewProviderChanged once (before calling
         // changeProviderAndSetting
         Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
@@ -1227,12 +1352,16 @@
                     false /* fallback */, null)};
 
         setupWithPackages(webviewPackages, true /* fallback logic enabled */, 1 /* numRelros */);
-        mTestSystemImpl.setPackageInfo(createPackageInfo(installedPackage, true /* enabled */,
-                    true /* valid */, true /* installed */));
-        mTestSystemImpl.setPackageInfo(createPackageInfo(uninstalledPackage, true /* enabled */,
-                    true /* valid */, (testUninstalled ? false : true) /* installed */,
-                    null /* signatures */, 0 /* updateTime */,
-                    (testHidden ? true : false) /* hidden */));
+        int secondaryUserId = 4;
+        mTestSystemImpl.addUser(secondaryUserId);
+
+        setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, webviewPackages);
+        mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(installedPackage,
+                true /* enabled */, true /* valid */, true /* installed */));
+        mTestSystemImpl.setPackageInfoForUser(secondaryUserId, createPackageInfo(uninstalledPackage,
+                true /* enabled */, true /* valid */,
+                (testUninstalled ? false : true) /* installed */, null /* signatures */,
+                0 /* updateTime */, (testHidden ? true : false) /* hidden */));
 
         // Start with the setting pointing to the uninstalled package
         mTestSystemImpl.updateUserSetting(null, uninstalledPackage);
@@ -1242,12 +1371,21 @@
         checkPreparationPhasesForPackage(installedPackage, 1 /* first preparation phase */);
     }
 
+    @Test
+    public void testFallbackEnabledIfPrimaryUninstalledSingleUser() {
+        checkFallbackEnabledIfPrimaryUninstalled(false /* multiUser */);
+    }
+
+    @Test
+    public void testFallbackEnabledIfPrimaryUninstalledMultiUser() {
+        checkFallbackEnabledIfPrimaryUninstalled(true /* multiUser */);
+    }
+
     /**
-     * Ensures that fallback becomes enabled if the primary package is uninstalled for the current
+     * Ensures that fallback becomes enabled at boot if the primary package is uninstalled for some
      * user.
      */
-    @Test
-    public void testFallbackEnabledIfPrimaryUninstalled() {
+    private void checkFallbackEnabledIfPrimaryUninstalled(boolean multiUser) {
         String primaryPackage = "primary";
         String fallbackPackage = "fallback";
         WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
@@ -1256,10 +1394,24 @@
             new WebViewProviderInfo(
                     fallbackPackage, "", true /* default available */, true /* fallback */, null)};
         setupWithPackages(packages, true /* fallback logic enabled */);
-        mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+        int secondaryUserId = 5;
+        if (multiUser) {
+            mTestSystemImpl.addUser(secondaryUserId);
+            // Install all packages for the primary user.
+            setEnabledAndValidPackageInfosForUser(TestSystemImpl.PRIMARY_USER_ID, packages);
+            // Only install fallback package for secondary user.
+            mTestSystemImpl.setPackageInfoForUser(secondaryUserId,
+                    createPackageInfo(primaryPackage, true /* enabled */,
+                            true /* valid */, false /* installed */));
+            mTestSystemImpl.setPackageInfoForUser(secondaryUserId,
+                    createPackageInfo(fallbackPackage, false /* enabled */,
+                            true /* valid */, true /* installed */));
+        } else {
+            mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
                     true /* valid */, false /* installed */));
-        mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, true /* enabled */,
+            mTestSystemImpl.setPackageInfo(createPackageInfo(fallbackPackage, false /* enabled */,
                     true /* valid */, true /* installed */));
+        }
 
         runWebViewBootPreparationOnMainSync();
         // Verify that we enable the fallback package
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
new file mode 100644
index 0000000..e1a22d9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.wm;
+
+import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
+import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
+import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY;
+import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
+import static android.graphics.GraphicBuffer.create;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskSnapshotCache}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.TaskSnapshotCacheTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
+
+    private TaskSnapshotCache mCache;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mCache = new TaskSnapshotCache(sWm, mLoader);
+    }
+
+    @Test
+    public void testAppRemoved() throws Exception {
+        final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
+        mCache.putSnapshot(window.getTask(), createSnapshot());
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+        mCache.onAppRemoved(window.mAppToken);
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+    }
+
+    @Test
+    public void testAppDied() throws Exception {
+        final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
+        mCache.putSnapshot(window.getTask(), createSnapshot());
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+        mCache.onAppDied(window.mAppToken);
+
+        // Should still be in the retrieval cache.
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+
+        // Trash retrieval cache.
+        for (int i = 0; i < 20; i++) {
+            mCache.putSnapshot(createWindow(null, FIRST_APPLICATION_WINDOW, "window").getTask(),
+                    createSnapshot());
+        }
+
+        // Should not be in cache anymore
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+    }
+
+    @Test
+    public void testTaskRemoved() throws Exception {
+        final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
+        mCache.putSnapshot(window.getTask(), createSnapshot());
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+        mCache.onTaskRemoved(window.getTask().mTaskId);
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
+                false /* restoreFromDisk */));
+    }
+
+    @Test
+    public void testRestoreFromDisk() throws Exception {
+        final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
+        mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot());
+        mPersister.waitForQueueEmpty();
+        assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+                false /* restoreFromDisk */));
+
+        // Load it from disk
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+                true /* restoreFromDisk */));
+
+        // Make sure it's in the cache now.
+        assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+                false /* restoreFromDisk */));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
new file mode 100644
index 0000000..dc008b5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.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.server.wm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+
+import com.android.internal.util.Predicate;
+import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+/**
+ * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
+ *
+ * runtest frameworks-services -c com.android.server.wm.TaskSnapshotPersisterLoaderTest
+ */
+@MediumTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
+
+    private static final String TEST_USER_NAME = "TaskSnapshotPersisterTest User";
+    private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
+
+    @Test
+    public void testPersistAndLoadSnapshot() {
+        mPersister.persistSnapshot(1 , sTestUserId, createSnapshot());
+        mPersister.waitForQueueEmpty();
+        final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
+                new File(sFilesDir.getPath() + "/snapshots/1.png") };
+        assertTrueForFiles(files, File::exists, " must exist");
+        final TaskSnapshot snapshot = mLoader.loadTask(1, sTestUserId);
+        assertNotNull(snapshot);
+        assertEquals(TEST_INSETS, snapshot.getContentInsets());
+        assertNotNull(snapshot.getSnapshot());
+        assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
+    }
+
+    private void assertTrueForFiles(File[] files, Predicate<File> predicate, String message) {
+        for (File file : files) {
+            assertTrue(file.getName() + message, predicate.apply(file));
+        }
+    }
+
+    @Test
+    public void testTaskRemovedFromRecents() {
+        mPersister.persistSnapshot(1, sTestUserId, createSnapshot());
+        mPersister.onTaskRemovedFromRecents(1, sTestUserId);
+        mPersister.waitForQueueEmpty();
+        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.proto").exists());
+        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.png").exists());
+    }
+
+    /**
+     * Tests that persisting a couple of snapshots is being throttled.
+     */
+    @Test
+    public void testThrottling() {
+        long ms = SystemClock.elapsedRealtime();
+        mPersister.persistSnapshot(1, sTestUserId, createSnapshot());
+        mPersister.persistSnapshot(2, sTestUserId, createSnapshot());
+        mPersister.persistSnapshot(3, sTestUserId, createSnapshot());
+        mPersister.persistSnapshot(4, sTestUserId, createSnapshot());
+        mPersister.persistSnapshot(5, sTestUserId, createSnapshot());
+        mPersister.persistSnapshot(6, sTestUserId, createSnapshot());
+        mPersister.waitForQueueEmpty();
+        assertTrue(SystemClock.elapsedRealtime() - ms > 500);
+    }
+
+    @Test
+    public void testGetTaskId() {
+        RemoveObsoleteFilesQueueItem removeObsoleteFilesQueueItem =
+                mPersister.new RemoveObsoleteFilesQueueItem(new ArraySet<>(), new int[] {});
+        assertEquals(-1, removeObsoleteFilesQueueItem.getTaskId("blablablulp"));
+        assertEquals(-1, removeObsoleteFilesQueueItem.getTaskId("nothing.err"));
+        assertEquals(-1, removeObsoleteFilesQueueItem.getTaskId("/invalid/"));
+        assertEquals(12, removeObsoleteFilesQueueItem.getTaskId("12.png"));
+        assertEquals(12, removeObsoleteFilesQueueItem.getTaskId("12.proto"));
+        assertEquals(1, removeObsoleteFilesQueueItem.getTaskId("1.png"));
+    }
+
+    @Test
+    public void testRemoveObsoleteFiles() {
+        mPersister.persistSnapshot(1, sTestUserId, createSnapshot());
+        mPersister.persistSnapshot(2, sTestUserId, createSnapshot());
+        final ArraySet<Integer> taskIds = new ArraySet<>();
+        taskIds.add(1);
+        mPersister.removeObsoleteFiles(taskIds, new int[] { sTestUserId });
+        mPersister.waitForQueueEmpty();
+        final File[] existsFiles = new File[] {
+                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
+                new File(sFilesDir.getPath() + "/snapshots/1.png") };
+        final File[] nonExistsFiles = new File[] {
+                new File(sFilesDir.getPath() + "/snapshots/2.proto"),
+                new File(sFilesDir.getPath() + "/snapshots/2.png") };
+        assertTrueForFiles(existsFiles, File::exists, " must exist");
+        assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
+    }
+
+    @Test
+    public void testRemoveObsoleteFiles_addedOneInTheMeantime() {
+        mPersister.persistSnapshot(1, sTestUserId, createSnapshot());
+        final ArraySet<Integer> taskIds = new ArraySet<>();
+        taskIds.add(1);
+        mPersister.removeObsoleteFiles(taskIds, new int[] { sTestUserId });
+        mPersister.persistSnapshot(2, sTestUserId, createSnapshot());
+        mPersister.waitForQueueEmpty();
+        final File[] existsFiles = new File[] {
+                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
+                new File(sFilesDir.getPath() + "/snapshots/1.png"),
+                new File(sFilesDir.getPath() + "/snapshots/2.proto"),
+                new File(sFilesDir.getPath() + "/snapshots/2.png") };
+        assertTrueForFiles(existsFiles, File::exists, " must exist");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
new file mode 100644
index 0000000..6fc6edb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.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.server.wm;
+
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
+import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.content.pm.UserInfo;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.UserManager;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import java.io.File;
+
+/**
+ * Base class for tests that use a {@link TaskSnapshotPersister}.
+ */
+class TaskSnapshotPersisterTestBase extends WindowTestsBase {
+
+    private static final String TEST_USER_NAME = "TaskSnapshotPersisterTest User";
+    private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
+
+    TaskSnapshotPersister mPersister;
+    TaskSnapshotLoader mLoader;
+    static int sTestUserId;
+    static File sFilesDir;
+    private static UserManager sUserManager;
+
+    @BeforeClass
+    public static void setUpUser() {
+        sUserManager = UserManager.get(InstrumentationRegistry.getContext());
+        sTestUserId = createUser(TEST_USER_NAME, 0);
+        sFilesDir = InstrumentationRegistry.getContext().getFilesDir();
+    }
+
+    @AfterClass
+    public static void tearDownUser() {
+        removeUser(sTestUserId);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mPersister = new TaskSnapshotPersister(
+                userId -> sFilesDir);
+        mLoader = new TaskSnapshotLoader(mPersister);
+        mPersister.start();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        cleanDirectory();
+    }
+
+    private static int createUser(String name, int flags) {
+        UserInfo user = sUserManager.createUser(name, flags);
+        if (user == null) {
+            Assert.fail("Error while creating the test user: " + TEST_USER_NAME);
+        }
+        return user.id;
+    }
+
+    private static void removeUser(int userId) {
+        if (!sUserManager.removeUser(userId)) {
+            Assert.fail("Error while removing the test user: " + TEST_USER_NAME);
+        }
+    }
+
+    private void cleanDirectory() {
+        for (File file : new File(sFilesDir, "snapshots").listFiles()) {
+            if (!file.isDirectory()) {
+                file.delete();
+            }
+        }
+    }
+
+    TaskSnapshot createSnapshot() {
+        GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
+                USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
+        Canvas c = buffer.lockCanvas();
+        c.drawColor(Color.RED);
+        buffer.unlockCanvasAndPost(c);
+        return new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, TEST_INSETS);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 24893a1..bb9bc9e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -17,13 +17,17 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import android.hardware.display.DisplayManagerGlobal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.DisplayInfo;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -88,6 +92,33 @@
         assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
     }
 
+    @Test
+    public void testReparentBetweenDisplays() throws Exception {
+        // Create first stack on primary display.
+        final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController(stack1.mStackId);
+        final TestTask task1 = (TestTask) taskController.mContainer;
+        task1.mOnDisplayChangedCalled = false;
+
+        // Create second display and put second stack on it.
+        final Display display = new Display(DisplayManagerGlobal.getInstance(),
+                sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
+                DEFAULT_DISPLAY_ADJUSTMENTS);
+        final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
+                new WallpaperController(sWm));
+        sWm.mRoot.addChild(dc, 1);
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+
+        // Reparent and check state.DisplayContent.java:2572
+        sWm.moveStackToDisplay(stack1.mStackId, dc.getDisplayId());
+        assertEquals(dc, stack1.getDisplayContent());
+        final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+        final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+        assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+        assertTrue(task1.mOnDisplayChangedCalled);
+    }
+
     private TaskStack addPinnedStack() {
         TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
         if (pinnedStack == null) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index f84bf60..7cd3f64 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -16,11 +16,16 @@
 
 package com.android.server.wm;
 
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
 import org.junit.Test;
 
+import android.hardware.display.DisplayManagerGlobal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.DisplayInfo;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -106,4 +111,33 @@
         assertEquals(0, ((TestTask) taskController.mContainer).positionInParent());
         assertEquals(1, ((TestTask) taskController2.mContainer).positionInParent());
     }
+
+    @Test
+    public void testReparentBetweenDisplays() throws Exception {
+        // Create first stack on primary display.
+        final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController(stack1.mStackId);
+        final TestTask task1 = (TestTask) taskController.mContainer;
+        task1.mOnDisplayChangedCalled = false;
+
+        // Create second display and put second stack on it.
+        final Display display = new Display(DisplayManagerGlobal.getInstance(),
+                sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
+                DEFAULT_DISPLAY_ADJUSTMENTS);
+        final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
+                new WallpaperController(sWm));
+        sWm.mRoot.addChild(dc, 1);
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+        final TestTaskWindowContainerController taskController2 =
+                new TestTaskWindowContainerController(stack2.mStackId);
+        final TestTask task2 = (TestTask) taskController2.mContainer;
+
+        // Reparent and check state
+        taskController.reparent(stack2.mStackId, 0);
+        assertEquals(stack2, task1.getParent());
+        assertEquals(0, task1.positionInParent());
+        assertEquals(1, task2.positionInParent());
+        assertTrue(task1.mOnDisplayChangedCalled);
+    }
 }
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 c0c8fb0..269b719 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -321,7 +321,7 @@
     @Override
     public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
-            int logo, int windowFlags, Configuration overrideConfig) {
+            int logo, int windowFlags, Configuration overrideConfig, int displayId) {
         return null;
     }
 
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 44d5055..813d263 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -23,6 +23,8 @@
 import org.junit.Assert;
 import org.junit.Before;
 
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.content.Context;
 import android.os.IBinder;
 import android.support.test.InstrumentationRegistry;
@@ -210,6 +212,7 @@
     class TestTask extends Task {
 
         boolean mShouldDeferRemoval = false;
+        boolean mOnDisplayChangedCalled = false;
 
         TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
                 Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
@@ -225,6 +228,12 @@
         int positionInParent() {
             return getParent().mChildren.indexOf(this);
         }
+
+        @Override
+        void onDisplayChanged(DisplayContent dc) {
+            super.onDisplayChanged(dc);
+            mOnDisplayChangedCalled = true;
+        }
     }
 
     /**
@@ -238,7 +247,7 @@
         }
 
         TestTaskWindowContainerController(int stackId) {
-            super(sNextTaskId++, stackId, 0 /* userId */, null /* bounds */,
+            super(sNextTaskId++, snapshot -> {}, stackId, 0 /* userId */, null /* bounds */,
                     EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, false /* homeTask*/,
                     false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */);
         }
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 3be04d4..6826975 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -31,11 +31,13 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
-import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
@@ -45,8 +47,6 @@
 
     private static final String PROP_VERIFY_STORAGE = "fw.verify_storage";
 
-    // TODO: pivot all methods to manual mode when quota isn't supported
-
     public static class Lifecycle extends SystemService {
         private StorageStatsService mService;
 
@@ -66,16 +66,37 @@
     private final UserManager mUser;
     private final PackageManager mPackage;
     private final StorageManager mStorage;
+
     private final Installer mInstaller;
 
     public StorageStatsService(Context context) {
-        mContext = context;
-        mAppOps = context.getSystemService(AppOpsManager.class);
-        mUser = context.getSystemService(UserManager.class);
-        mPackage = context.getSystemService(PackageManager.class);
-        mStorage = context.getSystemService(StorageManager.class);
+        mContext = Preconditions.checkNotNull(context);
+        mAppOps = Preconditions.checkNotNull(context.getSystemService(AppOpsManager.class));
+        mUser = Preconditions.checkNotNull(context.getSystemService(UserManager.class));
+        mPackage = Preconditions.checkNotNull(context.getPackageManager());
+        mStorage = Preconditions.checkNotNull(context.getSystemService(StorageManager.class));
+
         mInstaller = new Installer(context);
         mInstaller.onStart();
+        invalidateMounts();
+
+        mStorage.registerListener(new StorageEventListener() {
+            @Override
+            public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+                if ((vol.type == VolumeInfo.TYPE_PRIVATE)
+                        && (newState == VolumeInfo.STATE_MOUNTED)) {
+                    invalidateMounts();
+                }
+            }
+        });
+    }
+
+    private void invalidateMounts() {
+        try {
+            mInstaller.invalidateMounts();
+        } catch (InstallerException e) {
+            Slog.wtf(TAG, "Failed to invalidate mounts", e);
+        }
     }
 
     private void enforcePermission(int callingUid, String callingPackage) {
@@ -85,7 +106,7 @@
             case AppOpsManager.MODE_ALLOWED:
                 return;
             case AppOpsManager.MODE_DEFAULT:
-                mContext.enforceCallingPermission(
+                mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
                 return;
             default:
@@ -242,7 +263,7 @@
 
     private static void checkEquals(String msg, long expected, long actual) {
         if (expected != actual) {
-            Log.e(TAG, msg + " expected " + expected + " actual " + actual);
+            Slog.e(TAG, msg + " expected " + expected + " actual " + actual);
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 4bfc3df..6dfb48b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.IUidObserver;
 import android.app.admin.DevicePolicyManager;
 import android.app.usage.ConfigurationStats;
 import android.app.usage.IUsageStatsManager;
@@ -38,9 +39,9 @@
 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.ParceledListSlice;
 import android.content.pm.UserInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
@@ -49,6 +50,7 @@
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IDeviceIdleController;
 import android.os.Looper;
@@ -80,6 +82,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -103,6 +106,9 @@
     private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
     private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
 
+    private static final boolean ENABLE_KERNEL_UPDATES = false;
+    private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
+
     long mAppIdleScreenThresholdMillis;
     long mCheckIdleIntervalMillis;
     long mAppIdleWallclockThresholdMillis;
@@ -134,6 +140,7 @@
     private IBatteryStats mBatteryStats;
 
     private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
+    private final SparseIntArray mUidToKernelCounter = new SparseIntArray();
     private File mUsageStatsDir;
     long mRealTimeSnapshot;
     long mSystemTimeSnapshot;
@@ -235,6 +242,19 @@
                 postOneTimeCheckIdleStates();
             }
 
+            if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
+                try {
+                    ActivityManager.getService().registerUidObserver(mUidObserver,
+                            ActivityManager.UID_OBSERVER_PROCSTATE
+                                    | ActivityManager.UID_OBSERVER_GONE,
+                            ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            } else {
+                Slog.w(TAG, "Missing procfs interface: " + KERNEL_COUNTER_FILE);
+            }
+
             mSystemServicesReady = true;
         } else if (phase == PHASE_BOOT_COMPLETED) {
             setChargingState(getContext().getSystemService(BatteryManager.class).isCharging());
@@ -311,6 +331,39 @@
         }
     };
 
+    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+        @Override
+        public void onUidStateChanged(int uid, int procState) {
+            final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1;
+            synchronized (mUidToKernelCounter) {
+                final int oldCounter = mUidToKernelCounter.get(uid, 0);
+                if (newCounter != oldCounter) {
+                    mUidToKernelCounter.put(uid, newCounter);
+                    try {
+                        FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter);
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Failed to update counter set: " + e);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+            // Ignored
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) throws RemoteException {
+            onUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
+        }
+
+        @Override
+        public void onUidActive(int uid) throws RemoteException {
+            // Ignored
+        }
+    };
+
     @Override
     public void onStatsUpdated() {
         mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index db7a31a..fbbe636 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -656,6 +656,7 @@
             // send a sticky broadcast containing current USB state
             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                     | Intent.FLAG_RECEIVER_FOREGROUND);
             intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
             intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 7f182a4..4aff3d54 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -556,7 +556,9 @@
 
     private void sendPortChangedBroadcastLocked(PortInfo portInfo) {
         final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_CHANGED);
-        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.addFlags(
+                Intent.FLAG_RECEIVER_FOREGROUND |
+                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         intent.putExtra(UsbManager.EXTRA_PORT, portInfo.mUsbPort);
         intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus);
 
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index e03a14f..2e99b6e 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -971,7 +971,9 @@
     public void accessoryAttached(UsbAccessory accessory) {
         Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK |
+                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
 
         ArrayList<ResolveInfo> matches;
         String defaultPackage = null;
@@ -1364,7 +1366,9 @@
     private static Intent createDeviceAttachedIntent(UsbDevice device) {
         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK |
+                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         return intent;
     }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 24d5f09..7a55be4 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -182,6 +182,7 @@
         }
 
         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
 
         if (DEBUG) {
@@ -204,6 +205,7 @@
         }
 
         Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7d258a0..b7391b4 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -377,8 +377,16 @@
      */
     public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
 
+    /**
+     * Set by the framework to indicate that the {@link Connection} originated from a self-managed
+     * {@link ConnectionService}.
+     * <p>
+     * See {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.
+     */
+    public static final int PROPERTY_SELF_MANAGED = 1<<7;
+
     //**********************************************************************************************
-    // Next PROPERTY value: 1<<7
+    // Next PROPERTY value: 1<<8
     //**********************************************************************************************
 
     /**
@@ -681,6 +689,10 @@
             builder.append("Properties:");
         }
 
+        if (can(properties, PROPERTY_SELF_MANAGED)) {
+            builder.append(isLong ? " PROPERTY_SELF_MANAGED" : " self_mng");
+        }
+
         if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
             builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm");
         }
@@ -741,6 +753,7 @@
         public void onConnectionEvent(Connection c, String event, Bundle extras) {}
         /** @hide */
         public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {}
+        public void onAudioRouteChanged(Connection c, int audioRoute) {}
     }
 
     /**
@@ -2325,6 +2338,25 @@
     }
 
     /**
+     * Sets the audio route (speaker, bluetooth, etc...).  When this request is honored, there will
+     * be change to the {@link #getCallAudioState()}.
+     * <p>
+     * Used by self-managed {@link ConnectionService}s which wish to change the audio route for a
+     * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
+     * <p>
+     * See also {@link InCallService#setAudioRoute(int)}.
+     *
+     * @param route The audio route to use (one of {@link CallAudioState#ROUTE_BLUETOOTH},
+     *              {@link CallAudioState#ROUTE_EARPIECE}, {@link CallAudioState#ROUTE_SPEAKER}, or
+     *              {@link CallAudioState#ROUTE_WIRED_HEADSET}).
+     */
+    public final void setAudioRoute(int route) {
+        for (Listener l : mListeners) {
+            l.onAudioRouteChanged(this, route);
+        }
+    }
+
+    /**
      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
      *
      * @param state The new connection audio state.
@@ -2479,6 +2511,21 @@
      */
     public void onExtrasChanged(Bundle extras) {}
 
+    /**
+     * Notifies this {@link Connection} that its {@link ConnectionService} is responsible for
+     * displaying its incoming call user interface for the {@link Connection}.
+     * <p>
+     * Will only be called for incoming calls added via a self-managed {@link ConnectionService}
+     * (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}), where the {@link ConnectionService}
+     * should show its own incoming call user interface.
+     * <p>
+     * Where there are ongoing calls in other self-managed {@link ConnectionService}s, or in a
+     * regular {@link ConnectionService}, the Telecom framework will display its own incoming call
+     * user interface to allow the user to choose whether to answer the new incoming call and
+     * disconnect other ongoing calls, or to reject the new incoming call.
+     */
+    public void onShowIncomingCallUi() {}
+
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
         if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index aba38fe..2343462 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -33,6 +33,7 @@
     private final Bundle mExtras;
     private final int mVideoState;
     private final String mTelecomCallId;
+    private final boolean mShouldShowIncomingCallUi;
 
     /**
      * @param accountHandle The accountHandle which should be used to place the call.
@@ -43,7 +44,7 @@
             PhoneAccountHandle accountHandle,
             Uri handle,
             Bundle extras) {
-        this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null);
+        this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false);
     }
 
     /**
@@ -57,7 +58,7 @@
             Uri handle,
             Bundle extras,
             int videoState) {
-        this(accountHandle, handle, extras, videoState, null);
+        this(accountHandle, handle, extras, videoState, null, false);
     }
 
     /**
@@ -66,6 +67,10 @@
      * @param extras Application-specific extra data.
      * @param videoState Determines the video state for the connection.
      * @param telecomCallId The telecom call ID.
+     * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
+     *                                 {@code true} if the {@link ConnectionService} should show its
+     *                                 own incoming call UI for an incoming call.  When
+     *                                 {@code false}, Telecom shows the incoming call UI.
      * @hide
      */
     public ConnectionRequest(
@@ -73,12 +78,14 @@
             Uri handle,
             Bundle extras,
             int videoState,
-            String telecomCallId) {
+            String telecomCallId,
+            boolean shouldShowIncomingCallUi) {
         mAccountHandle = accountHandle;
         mAddress = handle;
         mExtras = extras;
         mVideoState = videoState;
         mTelecomCallId = telecomCallId;
+        mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
     }
 
     private ConnectionRequest(Parcel in) {
@@ -87,6 +94,7 @@
         mExtras = in.readParcelable(getClass().getClassLoader());
         mVideoState = in.readInt();
         mTelecomCallId = in.readString();
+        mShouldShowIncomingCallUi = in.readInt() == 1;
     }
 
     /**
@@ -129,6 +137,18 @@
         return mTelecomCallId;
     }
 
+    /**
+     * For a self-managed {@link ConnectionService}, indicates for an incoming call whether the
+     * {@link ConnectionService} should show its own incoming call UI for an incoming call.
+     *
+     * @return {@code true} if the {@link ConnectionService} should show its own incoming call UI.
+     * When {@code false}, Telecom shows the incoming call UI for the call.
+     * @hide
+     */
+    public boolean shouldShowIncomingCallUi() {
+        return mShouldShowIncomingCallUi;
+    }
+
     @Override
     public String toString() {
         return String.format("ConnectionRequest %s %s",
@@ -165,5 +185,6 @@
         destination.writeParcelable(mExtras, 0);
         destination.writeInt(mVideoState);
         destination.writeString(mTelecomCallId);
+        destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
     }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index b119e16..d0ccd55 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -42,10 +42,15 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * An abstract service that should be implemented by any apps which can make phone calls (VoIP or
- * otherwise) and want those calls to be integrated into the built-in phone app.
- * Once implemented, the {@code ConnectionService} needs two additional steps before it will be
- * integrated into the phone app:
+ * An abstract service that should be implemented by any apps which either:
+ * <ol>
+ *     <li>Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the
+ *     built-in phone app.  Referred to as a <b>system managed</b> {@link ConnectionService}.</li>
+ *     <li>Are a standalone calling app and don't want their calls to be integrated into the
+ *     built-in phone app.  Referred to as a <b>self managed</b> {@link ConnectionService}.</li>
+ * </ol>
+ * Once implemented, the {@link ConnectionService} needs to take the following steps so that Telecom
+ * will bind to it:
  * <p>
  * 1. <i>Registration in AndroidManifest.xml</i>
  * <br/>
@@ -63,16 +68,20 @@
  * <br/>
  * See {@link PhoneAccount} and {@link TelecomManager#registerPhoneAccount} for more information.
  * <p>
- * Once registered and enabled by the user in the phone app settings, telecom will bind to a
- * {@code ConnectionService} implementation when it wants that {@code ConnectionService} to place
- * a call or the service has indicated that is has an incoming call through
- * {@link TelecomManager#addNewIncomingCall}. The {@code ConnectionService} can then expect a call
- * to {@link #onCreateIncomingConnection} or {@link #onCreateOutgoingConnection} wherein it
- * should provide a new instance of a {@link Connection} object.  It is through this
- * {@link Connection} object that telecom receives state updates and the {@code ConnectionService}
+ * System managed {@link ConnectionService}s must be enabled by the user in the phone app settings
+ * before Telecom will bind to them.  Self-manged {@link ConnectionService}s must be granted the
+ * appropriate permission before Telecom will bind to them.
+ * <p>
+ * Once registered and enabled by the user in the phone app settings or granted permission, telecom
+ * will bind to a {@link ConnectionService} implementation when it wants that
+ * {@link ConnectionService} to place a call or the service has indicated that is has an incoming
+ * call through {@link TelecomManager#addNewIncomingCall}. The {@link ConnectionService} can then
+ * expect a call to {@link #onCreateIncomingConnection} or {@link #onCreateOutgoingConnection}
+ * wherein it should provide a new instance of a {@link Connection} object.  It is through this
+ * {@link Connection} object that telecom receives state updates and the {@link ConnectionService}
  * receives call-commands such as answer, reject, hold and disconnect.
  * <p>
- * When there are no more live calls, telecom will unbind from the {@code ConnectionService}.
+ * When there are no more live calls, telecom will unbind from the {@link ConnectionService}.
  */
 public abstract class ConnectionService extends Service {
     /**
@@ -1054,6 +1063,7 @@
             }
         }
 
+        @Override
         public void onExtrasRemoved(Connection c, List<String> keys) {
             String id = mIdByConnection.get(c);
             if (id != null) {
@@ -1061,7 +1071,6 @@
             }
         }
 
-
         @Override
         public void onConnectionEvent(Connection connection, String event, Bundle extras) {
             String id = mIdByConnection.get(connection);
@@ -1069,6 +1078,14 @@
                 mAdapter.onConnectionEvent(id, event, extras);
             }
         }
+
+        @Override
+        public void onAudioRouteChanged(Connection c, int audioRoute) {
+            String id = mIdByConnection.get(c);
+            if (id != null) {
+                mAdapter.setAudioRoute(id, audioRoute);
+            }
+        }
     };
 
     /** {@inheritDoc} */
@@ -1146,6 +1163,13 @@
                         connection.getDisconnectCause(),
                         createIdList(connection.getConferenceables()),
                         connection.getExtras()));
+
+        if (isIncoming && request.shouldShowIncomingCallUi() &&
+                (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) ==
+                        Connection.PROPERTY_SELF_MANAGED) {
+            // Tell ConnectionService to show its incoming call UX.
+            connection.onShowIncomingCallUi();
+        }
         if (isUnknown) {
             triggerConferenceRecalculate();
         }
@@ -1587,6 +1611,38 @@
     }
 
     /**
+     * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
+     * incoming {@link Connection} was denied.
+     * <p>
+     * Used when a self-managed {@link ConnectionService} attempts to create a new incoming
+     * {@link Connection}, but Telecom has determined that the call cannot be allowed at this time.
+     * The {@link ConnectionService} is responsible for silently rejecting the new incoming
+     * {@link Connection}.
+     * <p>
+     * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
+     *
+     * @param request The incoming connection request.
+     */
+    public void onCreateIncomingConnectionFailed(ConnectionRequest request) {
+    }
+
+    /**
+     * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
+     * outgoing {@link Connection} was denied.
+     * <p>
+     * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing
+     * {@link Connection}, but Telecom has determined that the call cannot be placed at this time.
+     * The {@link ConnectionService} is responisible for informing the user that the
+     * {@link Connection} cannot be made at this time.
+     * <p>
+     * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
+     *
+     * @param request The outgoing connection request.
+     */
+    public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {
+    }
+
+    /**
      * Trigger recalculate functinality for conference calls. This is used when a Telephony
      * Connection is part of a conference controller but is not yet added to Connection
      * Service and hence cannot be added to the conference call.
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index f3fada9..9542b73 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -515,6 +515,23 @@
     }
 
     /**
+     * Sets the audio route associated with a {@link Connection}.
+     *
+     * @param callId The unique ID of the call.
+     * @param audioRoute The new audio route (see {@code CallAudioState#ROUTE_*}).
+     */
+    void setAudioRoute(String callId, int audioRoute) {
+        Log.v(this, "setAudioRoute: %s %s", callId, CallAudioState.audioRouteToString(audioRoute));
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.setAudioRoute(callId, audioRoute, Log.getExternalSession());
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+
+    /**
      * Informs Telecom of a connection level event.
      *
      * @param callId The unique ID of the call.
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index afe5e33..cc437f9 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -67,6 +67,7 @@
     private static final int MSG_ON_CONNECTION_EVENT = 26;
     private static final int MSG_SET_CONNECTION_PROPERTIES = 27;
     private static final int MSG_SET_PULLING = 28;
+    private static final int MSG_SET_AUDIO_ROUTE = 29;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -289,6 +290,16 @@
                     }
                     break;
                 }
+                case MSG_SET_AUDIO_ROUTE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.setAudioRoute((String) args.arg1, args.argi1,
+                                (Session.Info) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
             }
         }
     };
@@ -507,6 +518,17 @@
         }
 
         @Override
+        public final void setAudioRoute(String connectionId, int audioRoute,
+                Session.Info sessionInfo) {
+
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = connectionId;
+            args.argi1 = audioRoute;
+            args.arg2 = sessionInfo;
+            mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, args).sendToTarget();
+        }
+
+        @Override
         public final void onConnectionEvent(String connectionId, String event, Bundle extras,
                 Session.Info sessionInfo) {
             SomeArgs args = SomeArgs.obtain();
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index ca54486..845a103 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -189,6 +189,21 @@
     public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 0x400;
 
     /**
+     * Flag indicating that this {@link PhoneAccount} is responsible for managing its own
+     * {@link Connection}s.  This type of {@link PhoneAccount} is ideal for use with standalone
+     * calling apps which do not wish to use the default phone app for {@link Connection} UX,
+     * but which want to leverage the call and audio routing capabilities of the Telecom framework.
+     * <p>
+     * When set, {@link Connection}s created by the self-managed {@link ConnectionService} will not
+     * be surfaced to implementations of the {@link InCallService} API.  Thus it is the
+     * responsibility of a self-managed {@link ConnectionService} to provide a user interface for
+     * its {@link Connection}s.
+     * <p>
+     * Self-managed {@link Connection}s will, however, be displayed on connected Bluetooth devices.
+     */
+    public static final int CAPABILITY_SELF_MANAGED = 0x800;
+
+    /**
      * URI scheme for telephone number URIs.
      */
     public static final String SCHEME_TEL = "tel";
@@ -692,6 +707,14 @@
         mIsEnabled = isEnabled;
     }
 
+    /**
+     * @return {@code true} if the {@link PhoneAccount} is self-managed, {@code false} otherwise.
+     * @hide
+     */
+    public boolean isSelfManaged() {
+        return (mCapabilities & CAPABILITY_SELF_MANAGED) == CAPABILITY_SELF_MANAGED;
+    }
+
     //
     // Parcelable implementation
     //
@@ -815,6 +838,9 @@
      */
     private String capabilitiesToString() {
         StringBuilder sb = new StringBuilder();
+        if (hasCapabilities(CAPABILITY_SELF_MANAGED)) {
+            sb.append("SelfManaged ");
+        }
         if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) {
             sb.append("SuppVideo ");
         }
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index d8a226a..0c7404a 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -389,6 +389,15 @@
         }
 
         @Override
+        public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) {
+            if (hasConnection(callId)) {
+                // TODO(3pcalls): handle this for remote connections.
+                // Likely we don't want to do anything since it doesn't make sense for self-managed
+                // connections to go through a connection mgr.
+            }
+        }
+
+        @Override
         public void onConnectionEvent(String callId, String event, Bundle extras,
                 Session.Info sessionInfo) {
             if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index f12886a..ba7b6a1 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -58,12 +58,15 @@
      * Input: get*Extra field {@link #EXTRA_PHONE_ACCOUNT_HANDLE} contains the component name of the
      * {@link android.telecom.ConnectionService} that Telecom should bind to. Telecom will then
      * ask the connection service for more information about the call prior to showing any UI.
+     *
+     * @deprecated Use {@link #addNewIncomingCall} instead.
      */
     public static final String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
 
     /**
      * Similar to {@link #ACTION_INCOMING_CALL}, but is used only by Telephony to add a new
      * sim-initiated MO call for carrier testing.
+     * @deprecated Use {@link #addNewUnknownCall} instead.
      * @hide
      */
     public static final String ACTION_NEW_UNKNOWN_CALL = "android.telecom.action.NEW_UNKNOWN_CALL";
@@ -1202,17 +1205,25 @@
 
     /**
      * Registers a new incoming call. A {@link ConnectionService} should invoke this method when it
-     * has an incoming call. The specified {@link PhoneAccountHandle} must have been registered
-     * with {@link #registerPhoneAccount} and the user must have enabled the corresponding
-     * {@link PhoneAccount}. This can be checked using {@link #getPhoneAccount}. Once invoked, this
-     * method will cause the system to bind to the {@link ConnectionService} associated with the
-     * {@link PhoneAccountHandle} and request additional information about the call
-     * (See {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming
+     * has an incoming call. For managed {@link ConnectionService}s, the specified
+     * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
+     * the user must have enabled the corresponding {@link PhoneAccount}.  This can be checked using
+     * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
+     * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
+     * <p>
+     * Once invoked, this method will cause the system to bind to the {@link ConnectionService}
+     * associated with the {@link PhoneAccountHandle} and request additional information about the
+     * call (See {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming
      * call UI.
      * <p>
-     * A {@link SecurityException} will be thrown if either the {@link PhoneAccountHandle} does not
-     * correspond to a registered {@link PhoneAccount} or the associated {@link PhoneAccount} is not
-     * currently enabled by the user.
+     * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
+     * the {@link PhoneAccountHandle} does not correspond to a registered {@link PhoneAccount} or
+     * the associated {@link PhoneAccount} is not currently enabled by the user.
+     * <p>
+     * For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if
+     * the {@link PhoneAccount} has {@link PhoneAccount#CAPABILITY_SELF_MANAGED} and the calling app
+     * does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
+     *
      * @param phoneAccount A {@link PhoneAccountHandle} registered with
      *            {@link #registerPhoneAccount}.
      * @param extras A bundle that will be passed through to
@@ -1379,7 +1390,8 @@
      * method-caller is either the user selected default dialer app or preloaded system dialer
      * app, then emergency calls will also be allowed.
      *
-     * Requires permission: {@link android.Manifest.permission#CALL_PHONE}
+     * Placing a call via a managed {@link ConnectionService} requires permission:
+     * {@link android.Manifest.permission#CALL_PHONE}
      *
      * Usage example:
      * <pre>
@@ -1396,11 +1408,20 @@
      *   <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li>
      *   <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li>
      * </ul>
+     * <p>
+     * An app which implements the self-managed {@link ConnectionService} API uses
+     * {@link #placeCall(Uri, Bundle)} to inform Telecom of a new outgoing call.  A self-managed
+     * {@link ConnectionService} must include {@link #EXTRA_PHONE_ACCOUNT_HANDLE} to specify its
+     * associated {@link android.telecom.PhoneAccountHandle}.
+     *
+     * Self-managed {@link ConnectionService}s require permission
+     * {@link android.Manifest.permission#MANAGE_OWN_CALLS}.
      *
      * @param address The address to make the call to.
      * @param extras Bundle of extras to use with the call.
      */
-    @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+    @RequiresPermission(anyOf = {android.Manifest.permission.CALL_PHONE,
+            android.Manifest.permission.MANAGE_OWN_CALLS})
     public void placeCall(Uri address, Bundle extras) {
         ITelecomService service = getTelecomService();
         if (service != null) {
@@ -1476,6 +1497,71 @@
         return result;
     }
 
+    /**
+     * Determines whether Telecom would permit an incoming call to be added via the
+     * {@link #addNewIncomingCall(PhoneAccountHandle, Bundle)} API for the specified
+     * {@link PhoneAccountHandle}.
+     * <p>
+     * A {@link ConnectionService} may not add a call for the specified {@link PhoneAccountHandle}
+     * in the following situations:
+     * <ul>
+     *     <li>{@link PhoneAccount} does not have property
+     *     {@link PhoneAccount#CAPABILITY_SELF_MANAGED} set (i.e. it is a managed
+     *     {@link ConnectionService}), and the active or held call limit has
+     *     been reached.</li>
+     *     <li>There is an ongoing emergency call.</li>
+     * </ul>
+     *
+     * @param phoneAccountHandle The {@link PhoneAccountHandle} the call will be added for.
+     * @return {@code true} if telecom will permit an incoming call to be added, {@code false}
+     *      otherwise.
+     */
+    public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                return service.isIncomingCallPermitted(phoneAccountHandle);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error isIncomingCallPermitted", e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines whether Telecom would permit an outgoing call to be placed via the
+     * {@link #placeCall(Uri, Bundle)} API for the specified {@link PhoneAccountHandle}.
+     * <p>
+     * A {@link ConnectionService} may not place a call for the specified {@link PhoneAccountHandle}
+     * in the following situations:
+     * <ul>
+     *     <li>{@link PhoneAccount} does not have property
+     *     {@link PhoneAccount#CAPABILITY_SELF_MANAGED} set (i.e. it is a managed
+     *     {@link ConnectionService}), and the active, held or ringing call limit has
+     *     been reached.</li>
+     *     <li>{@link PhoneAccount} has property {@link PhoneAccount#CAPABILITY_SELF_MANAGED} set
+     *     (i.e. it is a self-managed {@link ConnectionService} and there is an ongoing call in
+     *     another {@link ConnectionService}.</li>
+     *     <li>There is an ongoing emergency call.</li>
+     * </ul>
+     *
+     * @param phoneAccountHandle The {@link PhoneAccountHandle} the call will be added for.
+     * @return {@code true} if telecom will permit an outgoing call to be placed, {@code false}
+     *      otherwise.
+     */
+    public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                return service.isOutgoingCallPermitted(phoneAccountHandle);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error isOutgoingCallPermitted", e);
+            }
+        }
+        return false;
+    }
+
+
     private ITelecomService getTelecomService() {
         if (mTelecomServiceOverride != null) {
             return mTelecomServiceOverride;
diff --git a/telecomm/java/android/telecom/package-info.java b/telecomm/java/android/telecom/package-info.java
new file mode 100644
index 0000000..a4140e5
--- /dev/null
+++ b/telecomm/java/android/telecom/package-info.java
@@ -0,0 +1,59 @@
+/*
+ * 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
+ */
+
+/**
+ * The Android Telecom framework is responsible for managing calls on an Android device.  This can
+ * include SIM-based calls using the {@code Telephony} framework, VOIP calls using SIP (e.g. the
+ * {@code SipConnectionService}), or via a third-party VOIP
+ * {@link android.telecom.ConnectionService}.  Telecom acts as a switchboard, routing calls and
+ * audio focus between {@link android.telecom.Connection}s provided by
+ * {@link android.telecom.ConnectionService} implementations, and
+ * {@link android.telecom.InCallService} implementations which provide a user interface for calls.
+ * <p>
+ * Android supports the following calling use cases (with increasing level of complexity):
+ * <ul>
+ *     <li>Implement the self-managed {@link android.telecom.ConnectionService} API - this is ideal
+ *     for developers of standalone calling apps which do not wish to show their calls within the
+ *     default phone app, and do not wish to have other calls shown in their user interface.  Using
+ *     a self-managed {@link android.telecom.ConnectionService} implementation within your
+ *     standalone calling app helps you ensure that your app will interoperate not only with native
+ *     telephony calling on the device, but also other standalone calling apps implementing this
+ *     API.  It also manages audio routing and focus for you.</li>
+ *     <li>Implement the managed {@link android.telecom.ConnectionService} API - facilitates
+ *     development of a calling solution that relies on the existing device phone application (see
+ *     {@link android.telecom.TelecomManager#getDefaultDialerPackage()}) to provide the user
+ *     interface for calls.  An example might be a third party implementation of SIP calling, or a
+ *     VOIP calling service.  A {@link android.telecom.ConnectionService} alone provides only the
+ *     means of connecting calls, but has no associated user interface.</li>
+ *     <li>Implement the {@link android.telecom.InCallService} API - facilitates development of a
+ *     replacement for the device's default Phone/Dialer app.  The
+ *     {@link android.telecom.InCallService} alone does not have any calling capability and consists
+ *     of the user-interface side of calling only.  An {@link android.telecom.InCallService} must
+ *     handle all Calls the Telecom framework is aware of.  It must not make assumptions about the
+ *     nature of the calls (e.g. assuming calls are SIM-based telephony calls), and should not
+ *     implement calling restrictions based on any one {@link android.telecom.ConnectionService}
+ *     (e.g. it should not enforce Telephony restrictions for video calls).</li>
+ *     <li>Implement both the {@link android.telecom.InCallService} and
+ *     {@link android.telecom.ConnectionService} API - ideal if you wish to create your own
+ *     {@link android.telecom.ConnectionService} based calling solution, complete with its own
+ *     full user interface, while showing all other Android calls in the same user interface.  Using
+ *     this approach, you must still ensure that your {@link android.telecom.InCallService} makes
+ *     no assumption about the source of the calls it displays.  You must also ensure that your
+ *     {@link android.telecom.ConnectionService} implementation can still function without the
+ *     default phone app being set to your custom {@link android.telecom.InCallService}.</li>
+ * </ul>
+ */
+package android.telecom;
\ No newline at end of file
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 002c3bb..b58f8bc 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -102,6 +102,8 @@
 
     void removeExtras(String callId, in List<String> keys, in Session.Info sessionInfo);
 
+    void setAudioRoute(String callId, int audioRoute, in Session.Info sessionInfo);
+
     void onConnectionEvent(String callId, String event, in Bundle extras,
     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 5c412e7..6ca0bc5 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -249,4 +249,14 @@
     * @see TelecomServiceImpl#createManageBlockedNumbersIntent
     **/
     Intent createManageBlockedNumbersIntent();
+
+    /**
+     * @see TelecomServiceImpl#isIncomingCallPermitted
+     */
+    boolean isIncomingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
+
+    /**
+     * @see TelecomServiceImpl#isOutgoingCallPermitted
+     */
+    boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle);
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 288c9ab..a853d5c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -598,6 +598,38 @@
         "vvm_cellular_data_required_bool";
 
     /**
+     * The default OMTP visual voicemail client prefix to use. Defaulted to "//VVM"
+     */
+    public static final String KEY_VVM_CLIENT_PREFIX_STRING =
+            "vvm_client_prefix_string";
+
+    /**
+     * Whether to use SSL to connect to the visual voicemail IMAP server. Defaulted to false.
+     */
+    public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
+
+    /**
+     * A set of capabilities that should not be used even if it is reported by the visual voicemail
+     * IMAP CAPABILITY command.
+     */
+    public static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
+            "vvm_disabled_capabilities_string_array";
+
+    /**
+     * Whether legacy mode should be used when the visual voicemail client is disabled.
+     *
+     * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on
+     * the client side all network operations are disabled. SMSs are still monitored so a new
+     * message SYNC SMS will be translated to show a message waiting indicator, like traditional
+     * voicemails.
+     *
+     * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to
+     * function without the data cost.
+     */
+    public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL =
+            "vvm_legacy_mode_enabled_bool";
+
+    /**
      * Whether to prefetch audio data on new voicemail arrival, defaulted to true.
      */
     public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
@@ -605,10 +637,20 @@
     /**
      * The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
      * and carrier visual voicemail are not active at the same time.
+     *
+     * @deprecated use {@link #KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}.
      */
+    @Deprecated
     public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
 
     /**
+     * A list of the carrier's visual voicemail app package names to ensure that dialer visual
+     * voicemail and carrier visual voicemail are not active at the same time.
+     */
+    public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
+            "carrier_vvm_package_name_string_array";
+
+    /**
      * Flag specifying whether ICCID is showed in SIM Status screen, default to false.
      */
     public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -878,39 +920,6 @@
      public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
 
     /**
-     * A list of component name of carrier signalling receivers which are interested in intent
-     * android.intent.action.CARRIER_SIGNAL_REDIRECTED.
-     * Example:
-     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
-     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
-     * @hide
-     */
-    public static final String KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY =
-            "signal_redirection_receiver_string_array";
-
-    /**
-     * A list of component name of carrier signalling receivers which are interested in intent
-     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED.
-     * Example:
-     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
-     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
-     * @hide
-     */
-    public static final String KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY =
-            "signal_dcfailure_receiver_string_array";
-
-    /**
-     * A list of component name of carrier signalling receivers which are interested in intent
-     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE.
-     * Example:
-     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
-     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
-     * @hide
-     */
-    public static final String KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY =
-            "signal_pco_receiver_string_array";
-
-    /**
      * Defines carrier-specific actions which act upon
      * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
      * default carrier app
@@ -963,6 +972,42 @@
             "carrier_default_redirection_url_string_array";
 
     /**
+     * Each config includes the componentName of the carrier app, followed by a list of interesting
+     * signals(declared in the manifest) which could wake up the app.
+     * @see com.android.internal.telephony.TelephonyIntents
+     * Example:
+     * <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
+     * android.intent.action.CARRIER_SIGNAL_REDIRECTED,
+     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * </item>
+     * <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
+     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * </item>
+     * @hide
+     */
+    public static final String KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY =
+            "carrier_app_wake_signal_config";
+
+    /**
+     * Each config includes the componentName of the carrier app, followed by a list of interesting
+     * signals for the app during run-time. The list of signals(intents) are targeting on run-time
+     * broadcast receivers only, aiming to avoid unnecessary wake-ups and should not be declared in
+     * the app's manifest.
+     * @see com.android.internal.telephony.TelephonyIntents
+     * Example:
+     * <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
+     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+     * </item>
+     * <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
+     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+     * </item>
+     * @hide
+     */
+    public static final String KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY =
+            "carrier_app_no_wake_signal_config";
+
+    /**
      * Determines whether the carrier supports making non-emergency phone calls while the phone is
      * in emergency callback mode.  Default value is {@code true}, meaning that non-emergency calls
      * are allowed in emergency callback mode.
@@ -1305,8 +1350,13 @@
         sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
         sDefaults.putString(KEY_VVM_TYPE_STRING, "");
         sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
+        sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING,"//VVM");
+        sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL,false);
+        sDefaults.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL,false);
         sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true);
         sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
+        sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
         sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
@@ -1413,10 +1463,14 @@
         sDefaults.putString(KEY_RCS_CONFIG_SERVER_URL_STRING, "");
 
         // Carrier Signalling Receivers
-        sDefaults.putStringArray(KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY, null);
-        sDefaults.putStringArray(KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY, null);
-        sDefaults.putStringArray(KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY, null);
         sDefaults.putString(KEY_CARRIER_SETUP_APP_STRING, "");
+        sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
+                new String[]{
+                        "com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
+                                "android.intent.action.CARRIER_SIGNAL_REDIRECTED"
+                });
+        sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
+
 
         // Default carrier app configurations
         sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index eb838fa..a3f7c18 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5809,10 +5809,17 @@
      * Set the allowed carrier list for slotId
      * Require system privileges. In the future we may add this to carrier APIs.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     *
+     * <p>This method works only on devices with {@link
+     * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
+     *
      * @return The number of carriers set successfully. Should be length of
      * carrierList on success; -1 on error.
      * @hide
      */
+    @SystemApi
     public int setAllowedCarriers(int slotId, List<CarrierIdentifier> carriers) {
         try {
             ITelephony service = getITelephony();
@@ -5821,6 +5828,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
+        } catch (NullPointerException e) {
+            Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
         }
         return -1;
     }
@@ -5829,10 +5838,17 @@
      * Get the allowed carrier list for slotId.
      * Require system privileges. In the future we may add this to carrier APIs.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+     *
+     * <p>This method returns valid data on devices with {@link
+     * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled.
+     *
      * @return List of {@link android.telephony.CarrierIdentifier}; empty list
      * means all carriers are allowed.
      * @hide
      */
+    @SystemApi
     public List<CarrierIdentifier> getAllowedCarriers(int slotId) {
         try {
             ITelephony service = getITelephony();
@@ -5841,6 +5857,8 @@
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
+        } catch (NullPointerException e) {
+            Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
         }
         return new ArrayList<CarrierIdentifier>(0);
     }
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 0e9a485..3c36e42 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := core-oj core-libart junit framework
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
 
 LOCAL_MODULE:= android.test.runner
 
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index bcc68b3..b6e701e 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
+import android.app.Notification;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -513,6 +514,12 @@
     }
 
     @Override
+    public ComponentName startServiceInForeground(Intent service,
+            int id, Notification notification) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean stopService(Intent service) {
         throw new UnsupportedOperationException();
     }
@@ -525,6 +532,13 @@
 
     /** @hide */
     @Override
+    public ComponentName startServiceInForegroundAsUser(Intent service,
+            int id, Notification notification, UserHandle user) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
     public boolean stopServiceAsUser(Intent service, UserHandle user) {
         throw new UnsupportedOperationException();
     }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index c46d4a5..0c34f20 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -16,6 +16,7 @@
 
 package android.test.mock;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PackageInstallObserver;
@@ -43,7 +44,9 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.VersionedPackage;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Rect;
@@ -72,6 +75,12 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public PackageInfo getPackageInfo(VersionedPackage versionedPackage,
+            int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
     /** @hide */
     @Override
     public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
@@ -715,8 +724,7 @@
      * @hide - to match hiding in superclass
      */
     @Override
-    public void deletePackage(
-            String packageName, IPackageDeleteObserver observer, int flags) {
+    public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
         throw new UnsupportedOperationException();
     }
 
@@ -724,8 +732,8 @@
      * @hide - to match hiding in superclass
      */
     @Override
-    public void deletePackageAsUser(
-            String packageName, IPackageDeleteObserver observer, int flags, int userId) {
+    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer,
+            int flags, int userId) {
         throw new UnsupportedOperationException();
     }
 
@@ -818,6 +826,17 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public @NonNull List<SharedLibraryInfo> getSharedLibraries(int flags) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     /** @hide */
     @Override
     public @NonNull String getServicesSystemSharedLibraryPackageName() {
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
index d1efe7b..68fd662 100644
--- a/test-runner/tests/Android.mk
+++ b/test-runner/tests/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk
index e6f6c39..9435893 100644
--- a/tests/AppLaunch/Android.mk
+++ b/tests/AppLaunch/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_CERTIFICATE := platform
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test legacy-android-test
 
 include $(BUILD_PACKAGE)
 
diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk
index f2c07b3..59bc729 100644
--- a/tests/BrowserPowerTest/Android.mk
+++ b/tests/BrowserPowerTest/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
index 50926a6..1f14f03 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
@@ -25,13 +25,8 @@
 LOCAL_SRC_FILES += $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
-#LOCAL_STATIC_JAVA_LIBRARIES := filterframework-test-lib
-LOCAL_STATIC_JAVA_LIBRARIES += guava
+LOCAL_STATIC_JAVA_LIBRARIES := guava junit legacy-android-test
 
-#LOCAL_JAVA_LIBRARIES := filterframework-test-lib
-LOCAL_STATIC_JAVA_LIBRARIES := guava
-
-LOCAL_STATIC_JAVA_LIBRARIES +=
 LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_INSTRUMENTATION_FOR := SmartCamera
diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk
index 642c9e9..90de503 100644
--- a/tests/CanvasCompare/Android.mk
+++ b/tests/CanvasCompare/Android.mk
@@ -24,5 +24,6 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_PACKAGE)
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
index c2f89dd..99e84bd 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 # Include all test java files.
 LOCAL_SRC_FILES := \
 	$(call all-java-files-under, src)
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
index 5f3d0d9..c9f1161 100644
--- a/tests/CoreTests/android/Android.mk
+++ b/tests/CoreTests/android/Android.mk
@@ -7,6 +7,7 @@
 	$(call all-subdir-java-files)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt org.apache.http.legacy
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_PACKAGE_NAME := CoreTests
 
diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk
index acb46c5..4e15729 100644
--- a/tests/DataIdleTest/Android.mk
+++ b/tests/DataIdleTest/Android.mk
@@ -21,6 +21,7 @@
 
 LOCAL_PACKAGE_NAME := DataIdleTest
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # We need to sign it to get access to the network usage history.
diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk
index 2eb52f0..d2ec753 100644
--- a/tests/FrameworkPerf/Android.mk
+++ b/tests/FrameworkPerf/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_PACKAGE_NAME := FrameworkPerf
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_AAPT_FLAGS = -c 120dpi,240dpi,160dpi,161dpi,320dpi,nodpi
 
diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk
index 07b90f0..f8c8656 100644
--- a/tests/HierarchyViewerTest/Android.mk
+++ b/tests/HierarchyViewerTest/Android.mk
@@ -8,5 +8,6 @@
 LOCAL_PACKAGE_NAME := HierarchyViewerTest
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
index 0f1924c..6042471 100644
--- a/tests/ImfTest/tests/Android.mk
+++ b/tests/ImfTest/tests/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_PACKAGE_NAME := ImfTestTests
 
diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk
index 0ab793b..578e628 100644
--- a/tests/MemoryUsage/Android.mk
+++ b/tests/MemoryUsage/Android.mk
@@ -10,8 +10,9 @@
 
 LOCAL_CERTIFICATE := platform
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_PACKAGE)
 
 # Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index a63162d..dd9ff11 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -6,6 +6,7 @@
 LOCAL_CERTIFICATE := platform
 
 LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index e67134d..359484e 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -27,7 +27,7 @@
   LOCAL_SRC_FILES := src/android/hardware/soundtrigger/SoundTriggerTest.java
 endif
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target legacy-android-test
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := SoundTriggerTests
diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk
index e049c90..ed63e12 100644
--- a/tests/TtsTests/Android.mk
+++ b/tests/TtsTests/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_STATIC_JAVA_LIBRARIES := littlemock
+LOCAL_STATIC_JAVA_LIBRARIES := littlemock junit legacy-android-test
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := TtsTests
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index d62c30d..46b6403 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1103,6 +1103,29 @@
         UNAVAILABLE
     }
 
+    private static class CallbackInfo {
+        public final CallbackState state;
+        public final Network network;
+        public final Object arg;
+        public CallbackInfo(CallbackState s, Network n, Object o) {
+            state = s; network = n; arg = o;
+        }
+        public String toString() {
+            return String.format("%s (%s)", state, network);
+        }
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof CallbackInfo)) return false;
+            // Ignore timeMs, since it's unpredictable.
+            CallbackInfo other = (CallbackInfo) o;
+            return (state == other.state) && Objects.equals(network, other.network);
+        }
+        @Override
+        public int hashCode() {
+            return Objects.hash(state, network);
+        }
+    }
+
     /**
      * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
      * this class receives, by calling expectCallback() exactly once each time a callback is
@@ -1114,21 +1137,6 @@
         // the linger timeout.
         private final static int TIMEOUT_MS = 50;
 
-        private class CallbackInfo {
-            public final CallbackState state;
-            public final Network network;
-            public Object arg;
-            public CallbackInfo(CallbackState s, Network n, Object o) {
-                state = s; network = n; arg = o;
-            }
-            public String toString() { return String.format("%s (%s)", state, network); }
-            public boolean equals(Object o) {
-                if (!(o instanceof CallbackInfo)) return false;
-                // Ignore timeMs, since it's unpredictable.
-                CallbackInfo other = (CallbackInfo) o;
-                return state == other.state && Objects.equals(network, other.network);
-            }
-        }
         private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
 
         protected void setLastCallback(CallbackState state, Network network, Object o) {
@@ -1155,17 +1163,24 @@
             setLastCallback(CallbackState.LOST, network, null);
         }
 
+        CallbackInfo nextCallback(int timeoutMs) {
+            CallbackInfo cb = null;
+            try {
+                cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+            }
+            if (cb == null) {
+                // LinkedBlockingQueue.poll() returns null if it timeouts.
+                fail("Did not receive callback after " + timeoutMs + "ms");
+            }
+            return cb;
+        }
+
         void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
             CallbackInfo expected = new CallbackInfo(
                     state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
-            CallbackInfo actual;
-            try {
-                actual = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
-                assertEquals("Unexpected callback:", expected, actual);
-            } catch (InterruptedException e) {
-                fail("Did not receive expected " + expected + " after " + TIMEOUT_MS + "ms");
-                actual = null;  // Or the compiler can't tell it's never used uninitialized.
-            }
+            CallbackInfo actual = nextCallback(timeoutMs);
+            assertEquals("Unexpected callback:", expected, actual);
             if (state == CallbackState.LOSING) {
                 String msg = String.format(
                         "Invalid linger time value %d, must be between %d and %d",
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index b2a9a49..1e67769 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -16,10 +16,13 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.reset;
 
 import android.content.Context;
@@ -67,12 +70,13 @@
 
     @Test
     public void testDoesNothingBeforeStarted() {
-        UpstreamNetworkMonitor unm = new UpstreamNetworkMonitor(null, null, EVENT_UNM_UPDATE);
-        assertFalse(unm.mobileNetworkRequested());
-        // Given a null Context, and therefore a null ConnectivityManager,
-        // these would cause an exception, if they actually attempted anything.
-        unm.mobileUpstreamRequiresDun(true);
-        unm.mobileUpstreamRequiresDun(false);
+        assertTrue(mCM.hasNoCallbacks());
+        assertFalse(mUNM.mobileNetworkRequested());
+
+        mUNM.updateMobileRequiresDun(true);
+        assertTrue(mCM.hasNoCallbacks());
+        mUNM.updateMobileRequiresDun(false);
+        assertTrue(mCM.hasNoCallbacks());
     }
 
     @Test
@@ -83,7 +87,7 @@
         assertEquals(1, mCM.trackingDefault.size());
 
         mUNM.stop();
-        assertTrue(mCM.isEmpty());
+        assertTrue(mCM.hasNoCallbacks());
     }
 
     @Test
@@ -95,11 +99,11 @@
         assertTrue(mCM.isListeningForDun());
 
         mUNM.stop();
-        assertTrue(mCM.isEmpty());
+        assertTrue(mCM.hasNoCallbacks());
     }
 
     @Test
-    public void testCanRequestMobileNetwork() throws Exception {
+    public void testRequestsMobileNetwork() throws Exception {
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
@@ -107,22 +111,22 @@
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
-        mUNM.mobileUpstreamRequiresDun(false);
+        mUNM.updateMobileRequiresDun(false);
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
-        assertEquals(1, mCM.requested.size());
+        assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
         assertFalse(mCM.isDunRequested());
 
         mUNM.stop();
         assertFalse(mUNM.mobileNetworkRequested());
-        assertTrue(mCM.isEmpty());
+        assertTrue(mCM.hasNoCallbacks());
     }
 
     @Test
-    public void testCanRequestDunNetwork() throws Exception {
+    public void testRequestsDunNetwork() throws Exception {
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
@@ -130,33 +134,67 @@
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
-        mUNM.mobileUpstreamRequiresDun(true);
+        mUNM.updateMobileRequiresDun(true);
         assertFalse(mUNM.mobileNetworkRequested());
         assertEquals(0, mCM.requested.size());
 
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
-        assertEquals(1, mCM.requested.size());
+        assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
         assertTrue(mCM.isDunRequested());
 
         mUNM.stop();
         assertFalse(mUNM.mobileNetworkRequested());
-        assertTrue(mCM.isEmpty());
+        assertTrue(mCM.hasNoCallbacks());
+    }
+
+    @Test
+    public void testUpdateMobileRequiredDun() throws Exception {
+        mUNM.start();
+
+        // Test going from no-DUN to DUN correctly re-registers callbacks.
+        mUNM.updateMobileRequiresDun(false);
+        mUNM.registerMobileNetworkRequest();
+        assertTrue(mUNM.mobileNetworkRequested());
+        assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
+        assertFalse(mCM.isDunRequested());
+        mUNM.updateMobileRequiresDun(true);
+        assertTrue(mUNM.mobileNetworkRequested());
+        assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
+        assertTrue(mCM.isDunRequested());
+
+        // Test going from DUN to no-DUN correctly re-registers callbacks.
+        mUNM.updateMobileRequiresDun(false);
+        assertTrue(mUNM.mobileNetworkRequested());
+        assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
+        assertFalse(mCM.isDunRequested());
+
+        mUNM.stop();
+        assertFalse(mUNM.mobileNetworkRequested());
+    }
+
+    private void assertUpstreamTypeRequested(int upstreamType) throws Exception {
+        assertEquals(1, mCM.requested.size());
+        assertEquals(1, mCM.legacyTypeMap.size());
+        assertEquals(Integer.valueOf(upstreamType),
+                mCM.legacyTypeMap.values().iterator().next());
     }
 
     private static class TestConnectivityManager extends ConnectivityManager {
         public Set<NetworkCallback> trackingDefault = new HashSet<>();
         public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
         public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
+        public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();
 
         public TestConnectivityManager(Context ctx, IConnectivityManager svc) {
             super(ctx, svc);
         }
 
-        boolean isEmpty() {
+        boolean hasNoCallbacks() {
             return trackingDefault.isEmpty() &&
                    listening.isEmpty() &&
-                   requested.isEmpty();
+                   requested.isEmpty() &&
+                   legacyTypeMap.isEmpty();
         }
 
         boolean isListeningForDun() {
@@ -184,6 +222,17 @@
         }
 
         @Override
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb,
+                int timeoutMs, int legacyType) {
+            assertFalse(requested.containsKey(cb));
+            requested.put(cb, req);
+            assertFalse(legacyTypeMap.containsKey(cb));
+            if (legacyType != ConnectivityManager.TYPE_NONE) {
+                legacyTypeMap.put(cb, legacyType);
+            }
+        }
+
+        @Override
         public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
             assertFalse(listening.containsKey(cb));
             listening.put(cb, req);
@@ -203,6 +252,9 @@
                 listening.remove(cb);
             } else if (requested.containsKey(cb)) {
                 requested.remove(cb);
+                legacyTypeMap.remove(cb);
+            } else {
+                fail("Unexpected callback removed");
             }
 
             assertFalse(trackingDefault.contains(cb));
diff --git a/tests/permission/Android.mk b/tests/permission/Android.mk
index 31a0daf..54688c8 100644
--- a/tests/permission/Android.mk
+++ b/tests/permission/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := FrameworkPermissionTests
 
 include $(BUILD_PACKAGE)
diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk
index 392d398..43d1e37 100644
--- a/tests/utils/testutils/Android.mk
+++ b/tests/utils/testutils/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
+    legacy-android-test \
     mockito-target-minus-junit4
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index 565d2f0..d0026a2 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -131,6 +131,22 @@
         part = parts[index].string();
     }
 
+    if (parseWideColorGamut(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
+    if (parseHdr(part, &config)) {
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index].string();
+    }
+
     if (parseOrientation(part, &config)) {
         index++;
         if (index == N) {
@@ -250,7 +266,9 @@
 
     uint16_t minSdk = 0;
     if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
-                == ResTable_config::UI_MODE_TYPE_VR_HEADSET) {
+                == ResTable_config::UI_MODE_TYPE_VR_HEADSET
+            || config->colorimetry & ResTable_config::MASK_WIDE_COLOR_GAMUT
+            || config->colorimetry & ResTable_config::MASK_HDR) {
         minSdk = SDK_O;
     } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
         minSdk = SDK_MNC;
@@ -431,6 +449,46 @@
     return false;
 }
 
+bool parseWideColorGamut(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->colorimetry =
+                (out->colorimetry&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
+                | ResTable_config::WIDE_COLOR_GAMUT_ANY;
+        return true;
+    } else if (strcmp(name, "widecg") == 0) {
+        if (out) out->colorimetry =
+                (out->colorimetry&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
+                | ResTable_config::WIDE_COLOR_GAMUT_YES;
+        return true;
+    } else if (strcmp(name, "nowidecg") == 0) {
+        if (out) out->colorimetry =
+                (out->colorimetry&~ResTable_config::MASK_WIDE_COLOR_GAMUT)
+                | ResTable_config::WIDE_COLOR_GAMUT_NO;
+        return true;
+    }
+    return false;
+}
+
+bool parseHdr(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->colorimetry =
+                (out->colorimetry&~ResTable_config::MASK_HDR)
+                | ResTable_config::HDR_ANY;
+        return true;
+    } else if (strcmp(name, "highdr") == 0) {
+        if (out) out->colorimetry =
+                (out->colorimetry&~ResTable_config::MASK_HDR)
+                | ResTable_config::HDR_YES;
+        return true;
+    } else if (strcmp(name, "lowdr") == 0) {
+        if (out) out->colorimetry =
+                (out->colorimetry&~ResTable_config::MASK_HDR)
+                | ResTable_config::HDR_NO;
+        return true;
+    }
+    return false;
+}
+
 bool parseOrientation(const char* name, ResTable_config* out) {
     if (strcmp(name, kWildcardName) == 0) {
         if (out) out->orientation = out->ORIENTATION_ANY;
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
index 04c763f..a6dd252 100644
--- a/tools/aapt/AaptConfig.h
+++ b/tools/aapt/AaptConfig.h
@@ -61,6 +61,8 @@
 bool parseScreenLayoutSize(const char* str, android::ResTable_config* out = NULL);
 bool parseScreenLayoutLong(const char* str, android::ResTable_config* out = NULL);
 bool parseScreenRound(const char* name, android::ResTable_config* out = NULL);
+bool parseWideColorGamut(const char* name, android::ResTable_config* out = NULL);
+bool parseHdr(const char* name, android::ResTable_config* out = NULL);
 bool parseOrientation(const char* str, android::ResTable_config* out = NULL);
 bool parseUiModeType(const char* str, android::ResTable_config* out = NULL);
 bool parseUiModeNight(const char* str, android::ResTable_config* out = NULL);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 75a3160..045d68c 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -211,7 +211,7 @@
 bool isValidResourceType(const String8& type)
 {
     return type == "anim" || type == "animator" || type == "interpolator"
-        || type == "transition"
+        || type == "transition" || type == "font"
         || type == "drawable" || type == "layout"
         || type == "values" || type == "xml" || type == "raw"
         || type == "color" || type == "menu" || type == "mipmap";
diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp
index 8bb38ba..23f61e9 100644
--- a/tools/aapt/tests/AaptConfig_test.cpp
+++ b/tools/aapt/tests/AaptConfig_test.cpp
@@ -98,3 +98,33 @@
     EXPECT_EQ(SDK_MNC, config.sdkVersion);
     EXPECT_EQ(String8("notround-v23"), config.toString());
 }
+
+TEST(AaptConfigTest, WideColorGamutQualifier) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("widecg", &config));
+    EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_YES,
+              config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+    EXPECT_EQ(SDK_O, config.sdkVersion);
+    EXPECT_EQ(String8("widecg-v26"), config.toString());
+
+    EXPECT_TRUE(TestParse("nowidecg", &config));
+    EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_NO,
+              config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+    EXPECT_EQ(SDK_O, config.sdkVersion);
+    EXPECT_EQ(String8("nowidecg-v26"), config.toString());
+}
+
+TEST(AaptConfigTest, HdrQualifier) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("highdr", &config));
+    EXPECT_EQ(android::ResTable_config::HDR_YES,
+              config.colorimetry & android::ResTable_config::MASK_HDR);
+    EXPECT_EQ(SDK_O, config.sdkVersion);
+    EXPECT_EQ(String8("highdr-v26"), config.toString());
+
+    EXPECT_TRUE(TestParse("lowdr", &config));
+    EXPECT_EQ(android::ResTable_config::HDR_NO,
+              config.colorimetry & android::ResTable_config::MASK_HDR);
+    EXPECT_EQ(SDK_O, config.sdkVersion);
+    EXPECT_EQ(String8("lowdr-v26"), config.toString());
+}
\ No newline at end of file
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index b1bd401..5bea3ad 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -20,15 +20,16 @@
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
 
 #include "Locale.h"
 #include "SdkConstants.h"
-#include "util/StringPiece.h"
 #include "util/Util.h"
 
-namespace aapt {
-
 using android::ResTable_config;
+using android::StringPiece;
+
+namespace aapt {
 
 static const char* kWildcardName = "any";
 
@@ -205,6 +206,52 @@
   return false;
 }
 
+static bool parseWideColorGamut(const char* name, ResTable_config* out) {
+  if (strcmp(name, kWildcardName) == 0) {
+    if (out)
+      out->colorimetry =
+          (out->colorimetry & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
+          ResTable_config::WIDE_COLOR_GAMUT_ANY;
+    return true;
+  } else if (strcmp(name, "widecg") == 0) {
+    if (out)
+      out->colorimetry =
+          (out->colorimetry & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
+          ResTable_config::WIDE_COLOR_GAMUT_YES;
+    return true;
+  } else if (strcmp(name, "nowidecg") == 0) {
+    if (out)
+      out->colorimetry =
+          (out->colorimetry & ~ResTable_config::MASK_WIDE_COLOR_GAMUT) |
+          ResTable_config::WIDE_COLOR_GAMUT_NO;
+    return true;
+  }
+  return false;
+}
+
+static bool parseHdr(const char* name, ResTable_config* out) {
+  if (strcmp(name, kWildcardName) == 0) {
+    if (out)
+      out->colorimetry =
+          (out->colorimetry & ~ResTable_config::MASK_HDR) |
+          ResTable_config::HDR_ANY;
+    return true;
+  } else if (strcmp(name, "highdr") == 0) {
+    if (out)
+      out->colorimetry =
+          (out->colorimetry & ~ResTable_config::MASK_HDR) |
+          ResTable_config::HDR_YES;
+    return true;
+  } else if (strcmp(name, "lowdr") == 0) {
+    if (out)
+      out->colorimetry =
+          (out->colorimetry & ~ResTable_config::MASK_HDR) |
+          ResTable_config::HDR_NO;
+    return true;
+  }
+  return false;
+}
+
 static bool parseOrientation(const char* name, ResTable_config* out) {
   if (strcmp(name, kWildcardName) == 0) {
     if (out) out->orientation = out->ORIENTATION_ANY;
@@ -686,6 +733,20 @@
     }
   }
 
+  if (parseWideColorGamut(part_iter->c_str(), &config)) {
+    ++part_iter;
+    if (part_iter == parts_end) {
+      goto success;
+    }
+  }
+
+  if (parseHdr(part_iter->c_str(), &config)) {
+    ++part_iter;
+    if (part_iter == parts_end) {
+      goto success;
+    }
+  }
+
   if (parseOrientation(part_iter->c_str(), &config)) {
     ++part_iter;
     if (part_iter == parts_end) {
@@ -778,7 +839,9 @@
     ConfigDescription* config) {
   uint16_t min_sdk = 0;
   if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
-                == ResTable_config::UI_MODE_TYPE_VR_HEADSET) {
+                == ResTable_config::UI_MODE_TYPE_VR_HEADSET ||
+            config->colorimetry & ResTable_config::MASK_WIDE_COLOR_GAMUT ||
+            config->colorimetry & ResTable_config::MASK_HDR) {
         min_sdk = SDK_O;
   } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
     min_sdk = SDK_MARSHMALLOW;
@@ -849,6 +912,12 @@
   if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
     return !(o.screenLayout2 & MASK_SCREENROUND);
   }
+  if ((colorimetry | o.colorimetry) & MASK_HDR) {
+    return !(o.colorimetry & MASK_HDR);
+  }
+  if ((colorimetry | o.colorimetry) & MASK_WIDE_COLOR_GAMUT) {
+    return !(o.colorimetry & MASK_WIDE_COLOR_GAMUT);
+  }
   if (orientation || o.orientation) return (!o.orientation);
   if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
     return !(o.uiMode & MASK_UI_MODE_TYPE);
@@ -895,6 +964,9 @@
          !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT) ||
          !pred(screenLayout2 & MASK_SCREENROUND,
                o.screenLayout2 & MASK_SCREENROUND) ||
+         !pred(colorimetry & MASK_HDR, o.colorimetry & MASK_HDR) ||
+         !pred(colorimetry & MASK_WIDE_COLOR_GAMUT,
+               o.colorimetry & MASK_WIDE_COLOR_GAMUT) ||
          !pred(orientation, o.orientation) ||
          !pred(touchscreen, o.touchscreen) ||
          !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN) ||
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 97d0f38..65c9617 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -20,8 +20,7 @@
 #include <ostream>
 
 #include "androidfw/ResourceTypes.h"
-
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
 
 namespace aapt {
 
@@ -42,7 +41,7 @@
    * The resulting configuration has the appropriate sdkVersion defined
    * for backwards compatibility.
    */
-  static bool Parse(const StringPiece& str, ConfigDescription* out = nullptr);
+  static bool Parse(const android::StringPiece& str, ConfigDescription* out = nullptr);
 
   /**
    * If the configuration uses an axis that was added after
diff --git a/tools/aapt2/ConfigDescription_test.cpp b/tools/aapt2/ConfigDescription_test.cpp
index 1d22ce0..b88838a 100644
--- a/tools/aapt2/ConfigDescription_test.cpp
+++ b/tools/aapt2/ConfigDescription_test.cpp
@@ -18,9 +18,12 @@
 
 #include <string>
 
+#include "androidfw/StringPiece.h"
+
 #include "SdkConstants.h"
 #include "test/Test.h"
-#include "util/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
@@ -99,6 +102,36 @@
   EXPECT_EQ(std::string("notround-v23"), config.toString().string());
 }
 
+TEST(ConfigDescriptionTest, TestWideColorGamutQualifier) {
+  ConfigDescription config;
+  EXPECT_TRUE(TestParse("widecg", &config));
+  EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_YES,
+            config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+  EXPECT_EQ(SDK_O, config.sdkVersion);
+  EXPECT_EQ(std::string("widecg-v26"), config.toString().string());
+
+  EXPECT_TRUE(TestParse("nowidecg", &config));
+  EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_NO,
+            config.colorimetry & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
+  EXPECT_EQ(SDK_O, config.sdkVersion);
+  EXPECT_EQ(std::string("nowidecg-v26"), config.toString().string());
+}
+
+TEST(ConfigDescriptionTest, TestHdrQualifier) {
+  ConfigDescription config;
+  EXPECT_TRUE(TestParse("highdr", &config));
+  EXPECT_EQ(android::ResTable_config::HDR_YES,
+            config.colorimetry & android::ResTable_config::MASK_HDR);
+  EXPECT_EQ(SDK_O, config.sdkVersion);
+  EXPECT_EQ(std::string("highdr-v26"), config.toString().string());
+
+  EXPECT_TRUE(TestParse("lowdr", &config));
+  EXPECT_EQ(android::ResTable_config::HDR_NO,
+            config.colorimetry & android::ResTable_config::MASK_HDR);
+  EXPECT_EQ(SDK_O, config.sdkVersion);
+  EXPECT_EQ(std::string("lowdr-v26"), config.toString().string());
+}
+
 TEST(ConfigDescriptionTest, ParseVrAttribute) {
   ConfigDescription config;
   EXPECT_TRUE(TestParse("vrheadset", &config));
diff --git a/tools/aapt2/Diagnostics.h b/tools/aapt2/Diagnostics.h
index 5bc86a9..50e8b33 100644
--- a/tools/aapt2/Diagnostics.h
+++ b/tools/aapt2/Diagnostics.h
@@ -22,9 +22,9 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "Source.h"
-#include "util/StringPiece.h"
 #include "util/Util.h"
 
 namespace aapt {
@@ -38,7 +38,7 @@
  public:
   DiagMessage() = default;
 
-  explicit DiagMessage(const StringPiece& src) : source_(src) {}
+  explicit DiagMessage(const android::StringPiece& src) : source_(src) {}
 
   explicit DiagMessage(const Source& src) : source_(src) {}
 
@@ -59,6 +59,12 @@
   std::stringstream message_;
 };
 
+template <>
+inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) {
+  message_ << android::StringPiece16(value);
+  return *this;
+}
+
 struct IDiagnostics {
   virtual ~IDiagnostics() = default;
 
diff --git a/tools/aapt2/Flags.cpp b/tools/aapt2/Flags.cpp
index c98cd37..84977ab 100644
--- a/tools/aapt2/Flags.cpp
+++ b/tools/aapt2/Flags.cpp
@@ -21,20 +21,22 @@
 #include <string>
 #include <vector>
 
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
+
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 Flags& Flags::RequiredFlag(const StringPiece& name,
                            const StringPiece& description, std::string* value) {
   auto func = [value](const StringPiece& arg) -> bool {
-    *value = arg.ToString();
+    *value = arg.to_string();
     return true;
   };
 
-  flags_.push_back(
-      Flag{name.ToString(), description.ToString(), func, true, 1, false});
+  flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
   return *this;
 }
 
@@ -42,12 +44,11 @@
                                const StringPiece& description,
                                std::vector<std::string>* value) {
   auto func = [value](const StringPiece& arg) -> bool {
-    value->push_back(arg.ToString());
+    value->push_back(arg.to_string());
     return true;
   };
 
-  flags_.push_back(
-      Flag{name.ToString(), description.ToString(), func, true, 1, false});
+  flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
   return *this;
 }
 
@@ -55,12 +56,11 @@
                            const StringPiece& description,
                            Maybe<std::string>* value) {
   auto func = [value](const StringPiece& arg) -> bool {
-    *value = arg.ToString();
+    *value = arg.to_string();
     return true;
   };
 
-  flags_.push_back(
-      Flag{name.ToString(), description.ToString(), func, false, 1, false});
+  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
   return *this;
 }
 
@@ -68,12 +68,11 @@
                                const StringPiece& description,
                                std::vector<std::string>* value) {
   auto func = [value](const StringPiece& arg) -> bool {
-    value->push_back(arg.ToString());
+    value->push_back(arg.to_string());
     return true;
   };
 
-  flags_.push_back(
-      Flag{name.ToString(), description.ToString(), func, false, 1, false});
+  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
   return *this;
 }
 
@@ -81,12 +80,11 @@
                                const StringPiece& description,
                                std::unordered_set<std::string>* value) {
   auto func = [value](const StringPiece& arg) -> bool {
-    value->insert(arg.ToString());
+    value->insert(arg.to_string());
     return true;
   };
 
-  flags_.push_back(
-      Flag{name.ToString(), description.ToString(), func, false, 1, false});
+  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
   return *this;
 }
 
@@ -97,8 +95,7 @@
     return true;
   };
 
-  flags_.push_back(
-      Flag{name.ToString(), description.ToString(), func, false, 0, false});
+  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
   return *this;
 }
 
@@ -141,7 +138,7 @@
   for (size_t i = 0; i < args.size(); i++) {
     StringPiece arg = args[i];
     if (*(arg.data()) != '-') {
-      args_.push_back(arg.ToString());
+      args_.push_back(arg.to_string());
       continue;
     }
 
diff --git a/tools/aapt2/Flags.h b/tools/aapt2/Flags.h
index 9feff6b..3b3ae71 100644
--- a/tools/aapt2/Flags.h
+++ b/tools/aapt2/Flags.h
@@ -23,32 +23,30 @@
 #include <unordered_set>
 #include <vector>
 
+#include "androidfw/StringPiece.h"
+
 #include "util/Maybe.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
 class Flags {
  public:
-  Flags& RequiredFlag(const StringPiece& name, const StringPiece& description,
+  Flags& RequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
                       std::string* value);
-  Flags& RequiredFlagList(const StringPiece& name,
-                          const StringPiece& description,
+  Flags& RequiredFlagList(const android::StringPiece& name, const android::StringPiece& description,
                           std::vector<std::string>* value);
-  Flags& OptionalFlag(const StringPiece& name, const StringPiece& description,
+  Flags& OptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
                       Maybe<std::string>* value);
-  Flags& OptionalFlagList(const StringPiece& name,
-                          const StringPiece& description,
+  Flags& OptionalFlagList(const android::StringPiece& name, const android::StringPiece& description,
                           std::vector<std::string>* value);
-  Flags& OptionalFlagList(const StringPiece& name,
-                          const StringPiece& description,
+  Flags& OptionalFlagList(const android::StringPiece& name, const android::StringPiece& description,
                           std::unordered_set<std::string>* value);
-  Flags& OptionalSwitch(const StringPiece& name, const StringPiece& description,
+  Flags& OptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
                         bool* value);
 
-  void Usage(const StringPiece& command, std::ostream* out);
+  void Usage(const android::StringPiece& command, std::ostream* out);
 
-  bool Parse(const StringPiece& command, const std::vector<StringPiece>& args,
+  bool Parse(const android::StringPiece& command, const std::vector<android::StringPiece>& args,
              std::ostream* outError);
 
   const std::vector<std::string>& GetArgs();
@@ -57,7 +55,7 @@
   struct Flag {
     std::string name;
     std::string description;
-    std::function<bool(const StringPiece& value)> action;
+    std::function<bool(const android::StringPiece& value)> action;
     bool required;
     size_t num_args;
 
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
index 78f56c7a..7664fac 100644
--- a/tools/aapt2/Locale.cpp
+++ b/tools/aapt2/Locale.cpp
@@ -72,7 +72,7 @@
   return std::all_of(std::begin(str), std::end(str), ::isdigit);
 }
 
-bool LocaleValue::InitFromFilterString(const StringPiece& str) {
+bool LocaleValue::InitFromFilterString(const android::StringPiece& str) {
   // A locale (as specified in the filter) is an underscore separated name such
   // as "en_US", "en_Latn_US", or "en_US_POSIX".
   std::vector<std::string> parts = util::SplitAndLowercase(str, '_');
diff --git a/tools/aapt2/Locale.h b/tools/aapt2/Locale.h
index fc6c448..3d73b2e 100644
--- a/tools/aapt2/Locale.h
+++ b/tools/aapt2/Locale.h
@@ -21,8 +21,7 @@
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
-
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
 
 namespace aapt {
 
@@ -40,7 +39,7 @@
   /**
    * Initialize this LocaleValue from a config string.
    */
-  bool InitFromFilterString(const StringPiece& config);
+  bool InitFromFilterString(const android::StringPiece& config);
 
   /**
    * Initialize this LocaleValue from parts of a vector.
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index a2b216d..74d4019 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -17,7 +17,7 @@
 #include <iostream>
 #include <vector>
 
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
 
 namespace aapt {
 
@@ -33,10 +33,10 @@
   return 0;
 }
 
-extern int Compile(const std::vector<StringPiece>& args);
-extern int Link(const std::vector<StringPiece>& args);
-extern int Dump(const std::vector<StringPiece>& args);
-extern int Diff(const std::vector<StringPiece>& args);
+extern int Compile(const std::vector<android::StringPiece>& args);
+extern int Link(const std::vector<android::StringPiece>& args);
+extern int Dump(const std::vector<android::StringPiece>& args);
+extern int Diff(const std::vector<android::StringPiece>& args);
 
 }  // namespace aapt
 
@@ -45,12 +45,12 @@
     argv += 1;
     argc -= 1;
 
-    std::vector<aapt::StringPiece> args;
+    std::vector<android::StringPiece> args;
     for (int i = 1; i < argc; i++) {
       args.push_back(argv[i]);
     }
 
-    aapt::StringPiece command(argv[0]);
+    android::StringPiece command(argv[0]);
     if (command == "compile" || command == "c") {
       return aapt::Compile(args);
     } else if (command == "link" || command == "l") {
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index 3eef7aa7..fdabce1 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -19,6 +19,8 @@
 #include <map>
 #include <string>
 
+using android::StringPiece;
+
 namespace aapt {
 
 StringPiece ToString(ResourceType type) {
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 13330b5..1950ea3 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -24,11 +24,11 @@
 #include <tuple>
 #include <vector>
 
+#include "androidfw/StringPiece.h"
 #include "utils/JenkinsHash.h"
 
 #include "ConfigDescription.h"
 #include "Source.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
@@ -63,13 +63,13 @@
   kXml,
 };
 
-StringPiece ToString(ResourceType type);
+android::StringPiece ToString(ResourceType type);
 
 /**
  * Returns a pointer to a valid ResourceType, or nullptr if
  * the string was invalid.
  */
-const ResourceType* ParseResourceType(const StringPiece& str);
+const ResourceType* ParseResourceType(const android::StringPiece& str);
 
 /**
  * A resource's name. This can uniquely identify
@@ -81,7 +81,7 @@
   std::string entry;
 
   ResourceName() = default;
-  ResourceName(const StringPiece& p, ResourceType t, const StringPiece& e);
+  ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
 
   int compare(const ResourceName& other) const;
 
@@ -96,15 +96,15 @@
  * of the original string.
  */
 struct ResourceNameRef {
-  StringPiece package;
+  android::StringPiece package;
   ResourceType type = ResourceType::kRaw;
-  StringPiece entry;
+  android::StringPiece entry;
 
   ResourceNameRef() = default;
   ResourceNameRef(const ResourceNameRef&) = default;
   ResourceNameRef(ResourceNameRef&&) = default;
   ResourceNameRef(const ResourceName& rhs);  // NOLINT(implicit)
-  ResourceNameRef(const StringPiece& p, ResourceType t, const StringPiece& e);
+  ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
   ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
   ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
   ResourceNameRef& operator=(const ResourceName& rhs);
@@ -258,9 +258,9 @@
 // ResourceName implementation.
 //
 
-inline ResourceName::ResourceName(const StringPiece& p, ResourceType t,
-                                  const StringPiece& e)
-    : package(p.ToString()), type(t), entry(e.ToString()) {}
+inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
+                                  const android::StringPiece& e)
+    : package(p.to_string()), type(t), entry(e.to_string()) {}
 
 inline int ResourceName::compare(const ResourceName& other) const {
   int cmp = package.compare(other.package);
@@ -311,8 +311,8 @@
 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
     : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
 
-inline ResourceNameRef::ResourceNameRef(const StringPiece& p, ResourceType t,
-                                        const StringPiece& e)
+inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
+                                        const android::StringPiece& e)
     : package(p), type(t), entry(e) {}
 
 inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index b16def4..79379fe 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -29,6 +29,8 @@
 #include "util/Util.h"
 #include "xml/XmlPullParser.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 constexpr const char* sXliffNamespaceUri =
@@ -101,7 +103,7 @@
   StringPiece trimmed_comment = util::TrimWhitespace(res->comment);
   if (trimmed_comment.size() != res->comment.size()) {
     // Only if there was a change do we re-assign.
-    res->comment = trimmed_comment.ToString();
+    res->comment = trimmed_comment.to_string();
   }
 
   if (res->symbol_state) {
@@ -297,7 +299,7 @@
     // Extract the product name if it exists.
     if (Maybe<StringPiece> maybe_product =
             xml::FindNonEmptyAttribute(parser, "product")) {
-      parsed_resource.product = maybe_product.value().ToString();
+      parsed_resource.product = maybe_product.value().to_string();
     }
 
     // Parse the resource regardless of product.
@@ -383,7 +385,7 @@
     // Items have their type encoded in the type attribute.
     if (Maybe<StringPiece> maybe_type =
             xml::FindNonEmptyAttribute(parser, "type")) {
-      resource_type = maybe_type.value().ToString();
+      resource_type = maybe_type.value().to_string();
     } else {
       diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
                    << "<item> must have a 'type' attribute");
@@ -419,7 +421,7 @@
     }
 
     out_resource->name.type = ResourceType::kId;
-    out_resource->name.entry = maybe_name.value().ToString();
+    out_resource->name.entry = maybe_name.value().to_string();
     out_resource->value = util::make_unique<Id>();
     return true;
   }
@@ -436,7 +438,7 @@
     }
 
     out_resource->name.type = item_iter->second.type;
-    out_resource->name.entry = maybe_name.value().ToString();
+    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) {
@@ -461,7 +463,7 @@
         return false;
       }
 
-      out_resource->name.entry = maybe_name.value().ToString();
+      out_resource->name.entry = maybe_name.value().to_string();
     }
 
     // Call the associated parse method. The type will be filled in by the
@@ -484,7 +486,7 @@
     }
 
     out_resource->name.type = *parsed_type;
-    out_resource->name.entry = maybe_name.value().ToString();
+    out_resource->name.entry = maybe_name.value().to_string();
     out_resource->value =
         ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
     if (!out_resource->value) {
@@ -718,7 +720,7 @@
   const size_t depth = parser->depth();
   while (xml::XmlPullParser::NextChildNode(parser, depth)) {
     if (parser->event() == xml::XmlPullParser::Event::kComment) {
-      comment = util::TrimWhitespace(parser->comment()).ToString();
+      comment = util::TrimWhitespace(parser->comment()).to_string();
       continue;
     } else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
       // Skip text.
@@ -754,7 +756,7 @@
 
       ParsedResource child_resource;
       child_resource.name.type = *parsed_type;
-      child_resource.name.entry = maybe_name.value().ToString();
+      child_resource.name.entry = maybe_name.value().to_string();
       child_resource.id = next_id;
       child_resource.comment = std::move(comment);
       child_resource.source = item_source;
@@ -899,7 +901,7 @@
   const size_t depth = parser->depth();
   while (xml::XmlPullParser::NextChildNode(parser, depth)) {
     if (parser->event() == xml::XmlPullParser::Event::kComment) {
-      comment = util::TrimWhitespace(parser->comment()).ToString();
+      comment = util::TrimWhitespace(parser->comment()).to_string();
       continue;
     } else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
       // Skip text.
@@ -1288,7 +1290,7 @@
   const size_t depth = parser->depth();
   while (xml::XmlPullParser::NextChildNode(parser, depth)) {
     if (parser->event() == xml::XmlPullParser::Event::kComment) {
-      comment = util::TrimWhitespace(parser->comment()).ToString();
+      comment = util::TrimWhitespace(parser->comment()).to_string();
       continue;
     } else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
       // Ignore text.
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 11b1e5b..c12dacf 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -20,6 +20,7 @@
 #include <memory>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "ConfigDescription.h"
 #include "Diagnostics.h"
@@ -27,7 +28,6 @@
 #include "ResourceValues.h"
 #include "StringPool.h"
 #include "util/Maybe.h"
-#include "util/StringPiece.h"
 #include "xml/XmlPullParser.h"
 
 namespace aapt {
@@ -101,7 +101,7 @@
   bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource,
                      bool weak);
   Maybe<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
-                                               const StringPiece& tag);
+                                               const android::StringPiece& tag);
   bool ParseStyle(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
   bool ParseDeclareStyleable(xml::XmlPullParser* parser,
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 2463911..5762fb0 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -25,6 +25,8 @@
 #include "test/Test.h"
 #include "xml/XmlPullParser.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 constexpr const char* kXmlPreamble =
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 4e6a50a..dd78750 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -28,6 +28,8 @@
 #include <string>
 #include <tuple>
 
+using android::StringPiece;
+
 namespace aapt {
 
 static bool less_than_type(const std::unique_ptr<ResourceTableType>& lhs,
@@ -87,7 +89,7 @@
 
   std::unique_ptr<ResourceTablePackage> new_package =
       util::make_unique<ResourceTablePackage>();
-  new_package->name = name.ToString();
+  new_package->name = name.to_string();
   return packages.emplace(iter, std::move(new_package))->get();
 }
 
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index a0c3217..0fe966c 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -25,7 +25,9 @@
 #include "StringPool.h"
 #include "io/File.h"
 
-#include <android-base/macros.h>
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
 #include <functional>
 #include <map>
 #include <memory>
@@ -68,9 +70,8 @@
    */
   std::unique_ptr<Value> value;
 
-  ResourceConfigValue(const ConfigDescription& config,
-                      const StringPiece& product)
-      : config(config), product(product.ToString()) {}
+  ResourceConfigValue(const ConfigDescription& config, const android::StringPiece& product)
+      : config(config), product(product.to_string()) {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
@@ -105,13 +106,13 @@
    */
   std::vector<std::unique_ptr<ResourceConfigValue>> values;
 
-  explicit ResourceEntry(const StringPiece& name) : name(name.ToString()) {}
+  explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
 
   ResourceConfigValue* FindValue(const ConfigDescription& config);
   ResourceConfigValue* FindValue(const ConfigDescription& config,
-                                 const StringPiece& product);
+                                 const android::StringPiece& product);
   ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config,
-                                         const StringPiece& product);
+                                         const android::StringPiece& product);
   std::vector<ResourceConfigValue*> findAllValues(
       const ConfigDescription& config);
   std::vector<ResourceConfigValue*> FindValuesIf(
@@ -150,8 +151,8 @@
 
   explicit ResourceTableType(const ResourceType type) : type(type) {}
 
-  ResourceEntry* FindEntry(const StringPiece& name);
-  ResourceEntry* FindOrCreateEntry(const StringPiece& name);
+  ResourceEntry* FindEntry(const android::StringPiece& name);
+  ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
@@ -195,22 +196,19 @@
                                                Value* incoming);
 
   bool AddResource(const ResourceNameRef& name, const ConfigDescription& config,
-                   const StringPiece& product, std::unique_ptr<Value> value,
+                   const android::StringPiece& product, std::unique_ptr<Value> value,
                    IDiagnostics* diag);
 
   bool AddResource(const ResourceNameRef& name, const ResourceId& res_id,
-                   const ConfigDescription& config, const StringPiece& product,
+                   const ConfigDescription& config, const android::StringPiece& product,
                    std::unique_ptr<Value> value, IDiagnostics* diag);
 
-  bool AddFileReference(const ResourceNameRef& name,
-                        const ConfigDescription& config, const Source& source,
-                        const StringPiece& path, IDiagnostics* diag);
+  bool AddFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+                        const Source& source, const android::StringPiece& path, IDiagnostics* diag);
 
-  bool AddFileReferenceAllowMangled(const ResourceNameRef& name,
-                                    const ConfigDescription& config,
-                                    const Source& source,
-                                    const StringPiece& path, io::IFile* file,
-                                    IDiagnostics* diag);
+  bool AddFileReferenceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config,
+                                    const Source& source, const android::StringPiece& path,
+                                    io::IFile* file, IDiagnostics* diag);
 
   /**
    * Same as AddResource, but doesn't verify the validity of the name. This is
@@ -219,18 +217,13 @@
    * mangled
    * names.
    */
-  bool AddResourceAllowMangled(const ResourceNameRef& name,
-                               const ConfigDescription& config,
-                               const StringPiece& product,
-                               std::unique_ptr<Value> value,
+  bool AddResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config,
+                               const android::StringPiece& product, std::unique_ptr<Value> value,
                                IDiagnostics* diag);
 
-  bool AddResourceAllowMangled(const ResourceNameRef& name,
-                               const ResourceId& id,
-                               const ConfigDescription& config,
-                               const StringPiece& product,
-                               std::unique_ptr<Value> value,
-                               IDiagnostics* diag);
+  bool AddResourceAllowMangled(const ResourceNameRef& name, const ResourceId& id,
+                               const ConfigDescription& config, const android::StringPiece& product,
+                               std::unique_ptr<Value> value, IDiagnostics* diag);
 
   bool SetSymbolState(const ResourceNameRef& name, const ResourceId& res_id,
                       const Symbol& symbol, IDiagnostics* diag);
@@ -273,28 +266,23 @@
    * represent the
    * 'current' package before it is known to the ResourceTable.
    */
-  ResourceTablePackage* FindPackage(const StringPiece& name);
+  ResourceTablePackage* FindPackage(const android::StringPiece& name);
 
   ResourceTablePackage* FindPackageById(uint8_t id);
 
-  ResourceTablePackage* CreatePackage(const StringPiece& name,
-                                      Maybe<uint8_t> id = {});
+  ResourceTablePackage* CreatePackage(const android::StringPiece& name, Maybe<uint8_t> id = {});
 
  private:
-  ResourceTablePackage* FindOrCreatePackage(const StringPiece& name);
+  ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name);
 
   bool AddResourceImpl(const ResourceNameRef& name, const ResourceId& res_id,
-                       const ConfigDescription& config,
-                       const StringPiece& product, std::unique_ptr<Value> value,
-                       const char* valid_chars,
-                       const CollisionResolverFunc& conflict_resolver,
-                       IDiagnostics* diag);
+                       const ConfigDescription& config, const android::StringPiece& product,
+                       std::unique_ptr<Value> value, const char* valid_chars,
+                       const CollisionResolverFunc& conflict_resolver, IDiagnostics* diag);
 
-  bool AddFileReferenceImpl(const ResourceNameRef& name,
-                            const ConfigDescription& config,
-                            const Source& source, const StringPiece& path,
-                            io::IFile* file, const char* valid_chars,
-                            IDiagnostics* diag);
+  bool AddFileReferenceImpl(const ResourceNameRef& name, const ConfigDescription& config,
+                            const Source& source, const android::StringPiece& path, io::IFile* file,
+                            const char* valid_chars, IDiagnostics* diag);
 
   bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
                           const Symbol& symbol, const char* valid_chars,
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index fce9b33..1123967 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -26,6 +26,9 @@
 #include "util/Files.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+using android::StringPiece16;
+
 namespace aapt {
 namespace ResourceUtils {
 
@@ -59,7 +62,7 @@
     name_out.entry =
         util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen));
   } else if (name_in.name8) {
-    name_out.entry = StringPiece(name_in.name8, name_in.nameLen).ToString();
+    name_out.entry.assign(name_in.name8, name_in.nameLen);
   } else {
     return {};
   }
@@ -303,9 +306,7 @@
     p++;
   }
 
-  ref.name =
-      ResourceName(package.ToString(), ResourceType::kAttr,
-                   name.empty() ? trimmed_str.ToString() : name.ToString());
+  ref.name = ResourceName(package, ResourceType::kAttr, name.empty() ? trimmed_str : name);
   return Maybe<Reference>(std::move(ref));
 }
 
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 9766f6a..bd3a8e3 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -20,10 +20,11 @@
 #include <functional>
 #include <memory>
 
+#include "androidfw/StringPiece.h"
+
 #include "NameMangler.h"
 #include "Resource.h"
 #include "ResourceValues.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 namespace ResourceUtils {
@@ -37,8 +38,8 @@
  * individual extracted piece to verify that the pieces are valid.
  * Returns false if there was no package but a ':' was present.
  */
-bool ExtractResourceName(const StringPiece& str, StringPiece* out_package,
-                         StringPiece* out_type, StringPiece* out_entry);
+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
@@ -46,7 +47,7 @@
  * `out_resource` set to the parsed resource name and `out_private` set to true
  * if a '*' prefix was present.
  */
-bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_resource,
+bool ParseResourceName(const android::StringPiece& str, ResourceNameRef* out_resource,
                        bool* out_private = nullptr);
 
 /*
@@ -57,28 +58,27 @@
  * If '+' was present in the reference, `out_create` is set to true.
  * If '*' was present in the reference, `out_private` is set to true.
  */
-bool ParseReference(const StringPiece& str, ResourceNameRef* out_reference,
+bool ParseReference(const android::StringPiece& str, ResourceNameRef* out_reference,
                     bool* out_create = nullptr, bool* out_private = nullptr);
 
 /*
  * Returns true if the string is in the form of a resource reference
  * (@[+][package:]type/name).
  */
-bool IsReference(const StringPiece& str);
+bool IsReference(const android::StringPiece& str);
 
 /*
  * Returns true if the string was parsed as an attribute reference
  * (?[package:][type/]name),
  * with `out_reference` set to the parsed reference.
  */
-bool ParseAttributeReference(const StringPiece& str,
-                             ResourceNameRef* out_reference);
+bool ParseAttributeReference(const android::StringPiece& str, ResourceNameRef* out_reference);
 
 /**
  * Returns true if the string is in the form of an attribute
  * reference(?[package:][type/]name).
  */
-bool IsAttributeReference(const StringPiece& str);
+bool IsAttributeReference(const android::StringPiece& str);
 
 /**
  * Convert an android::ResTable::resource_name to an aapt::ResourceName struct.
@@ -90,22 +90,22 @@
  * Returns a boolean value if the string is equal to TRUE, true, True, FALSE,
  * false, or False.
  */
-Maybe<bool> ParseBool(const StringPiece& str);
+Maybe<bool> ParseBool(const android::StringPiece& str);
 
 /**
  * Returns a uint32_t if the string is an integer.
  */
-Maybe<uint32_t> ParseInt(const StringPiece& str);
+Maybe<uint32_t> ParseInt(const android::StringPiece& str);
 
 /**
  * Returns an ID if it the string represented a valid ID.
  */
-Maybe<ResourceId> ParseResourceId(const StringPiece& str);
+Maybe<ResourceId> ParseResourceId(const android::StringPiece& str);
 
 /**
  * Parses an SDK version, which can be an integer, or a letter from A-Z.
  */
-Maybe<int> ParseSdkVersion(const StringPiece& str);
+Maybe<int> ParseSdkVersion(const android::StringPiece& str);
 
 /*
  * Returns a Reference, or None Maybe instance if the string `str` was parsed as
@@ -118,8 +118,7 @@
  * ?[package:]style/<entry> or
  * <package>:[style/]<entry>
  */
-Maybe<Reference> ParseStyleParentReference(const StringPiece& str,
-                                           std::string* out_error);
+Maybe<Reference> ParseStyleParentReference(const android::StringPiece& str, std::string* out_error);
 
 /*
  * Returns a Reference if the string `str` was parsed as a valid XML attribute
@@ -128,7 +127,7 @@
  *
  * package:entry
  */
-Maybe<Reference> ParseXmlAttributeName(const StringPiece& str);
+Maybe<Reference> ParseXmlAttributeName(const android::StringPiece& str);
 
 /*
  * Returns a Reference object if the string was parsed as a resource or
@@ -137,52 +136,52 @@
  * if
  * the '+' was present in the string.
  */
-std::unique_ptr<Reference> TryParseReference(const StringPiece& str,
+std::unique_ptr<Reference> TryParseReference(const android::StringPiece& str,
                                              bool* out_create = nullptr);
 
 /*
  * Returns a BinaryPrimitve object representing @null or @empty if the string
  * was parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseNullOrEmpty(const StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseNullOrEmpty(const android::StringPiece& str);
 
 /*
  * Returns a BinaryPrimitve object representing a color if the string was parsed
  * as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseColor(const android::StringPiece& str);
 
 /*
  * Returns a BinaryPrimitve object representing a boolean if the string was
  * parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseBool(const android::StringPiece& str);
 
 /*
  * Returns a BinaryPrimitve object representing an integer if the string was
  * parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseInt(const android::StringPiece& str);
 
 /*
  * Returns a BinaryPrimitve object representing a floating point number
  * (float, dimension, etc) if the string was parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseFloat(const android::StringPiece& str);
 
 /*
  * Returns a BinaryPrimitve object representing an enum symbol if the string was
  * parsed as one.
  */
 std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
-                                                    const StringPiece& str);
+                                                    const android::StringPiece& str);
 
 /*
  * Returns a BinaryPrimitve object representing a flag symbol if the string was
  * parsed as one.
  */
 std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr,
-                                                    const StringPiece& str);
+                                                    const android::StringPiece& str);
 /*
  * Try to convert a string to an Item for the given attribute. The attribute
  * will
@@ -191,11 +190,11 @@
  * reference to an ID that must be created (@+id/foo).
  */
 std::unique_ptr<Item> TryParseItemForAttribute(
-    const StringPiece& value, const Attribute* attr,
+    const android::StringPiece& value, const Attribute* attr,
     const std::function<void(const ResourceName&)>& on_create_reference = {});
 
 std::unique_ptr<Item> TryParseItemForAttribute(
-    const StringPiece& value, uint32_t type_mask,
+    const android::StringPiece& value, uint32_t type_mask,
     const std::function<void(const ResourceName&)>& on_create_reference = {});
 
 uint32_t AndroidTypeToAttributeTypeMask(uint16_t type);
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index f9c500b..048c692 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -48,8 +48,7 @@
   EXPECT_EQ(ResourceNameRef("android", ResourceType::kColor, "foo"), actual);
   EXPECT_TRUE(actual_priv);
 
-  EXPECT_FALSE(
-      ResourceUtils::ParseResourceName(StringPiece(), &actual, &actual_priv));
+  EXPECT_FALSE(ResourceUtils::ParseResourceName(android::StringPiece(), &actual, &actual_priv));
 }
 
 TEST(ResourceUtilsTest, ParseReferenceWithNoPackage) {
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index ea73615..d380f8d 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
 
 #include "Diagnostics.h"
 #include "Resource.h"
@@ -73,7 +74,7 @@
    */
   const std::string& GetComment() const { return comment_; }
 
-  void SetComment(const StringPiece& str) { comment_ = str.ToString(); }
+  void SetComment(const android::StringPiece& str) { comment_ = str.to_string(); }
 
   void SetComment(std::string&& str) { comment_ = std::move(str); }
 
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index c7f920a..e806714 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -21,6 +21,8 @@
 #include <unordered_map>
 #include <vector>
 
+using android::StringPiece;
+
 namespace aapt {
 
 static const char* sDevelopmentSdkCodeName = "O";
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 5352b53..98ba94b 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -19,6 +19,8 @@
 
 #include <utility>
 
+#include "androidfw/StringPiece.h"
+
 #include "Resource.h"
 
 namespace aapt {
@@ -52,7 +54,7 @@
 
 size_t FindAttributeSdkLevel(const ResourceId& id);
 size_t FindAttributeSdkLevel(const ResourceName& name);
-std::pair<StringPiece, int> GetDevelopmentSdkCodeNameAndVersion();
+std::pair<android::StringPiece, int> GetDevelopmentSdkCodeNameAndVersion();
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
index 459a8e6..d7f2a66 100644
--- a/tools/aapt2/Source.h
+++ b/tools/aapt2/Source.h
@@ -20,8 +20,9 @@
 #include <ostream>
 #include <string>
 
+#include "androidfw/StringPiece.h"
+
 #include "util/Maybe.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
@@ -35,12 +36,11 @@
 
   Source() = default;
 
-  inline Source(const StringPiece& path)
-      : path(path.ToString()) {  // NOLINT(implicit)
+  inline Source(const android::StringPiece& path) : path(path.to_string()) {  // NOLINT(implicit)
   }
 
-  inline Source(const StringPiece& path, size_t line)
-      : path(path.ToString()), line(line) {}
+  inline Source(const android::StringPiece& path, size_t line)
+      : path(path.to_string()), line(line) {}
 
   inline Source WithLine(size_t line) const { return Source(path, line); }
 };
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
index 3032829..d968d73 100644
--- a/tools/aapt2/StringPool.cpp
+++ b/tools/aapt2/StringPool.cpp
@@ -22,11 +22,13 @@
 
 #include "android-base/logging.h"
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
 
 #include "util/BigBuffer.h"
-#include "util/StringPiece.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 StringPool::Ref::Ref() : entry_(nullptr) {}
@@ -140,7 +142,7 @@
   }
 
   Entry* entry = new Entry();
-  entry->value = str.ToString();
+  entry->value = str.to_string();
   entry->context = context;
   entry->index = strings_.size();
   entry->ref_ = 0;
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
index a4f556c..d0ce489 100644
--- a/tools/aapt2/StringPool.h
+++ b/tools/aapt2/StringPool.h
@@ -23,9 +23,10 @@
 #include <unordered_map>
 #include <vector>
 
+#include "androidfw/StringPiece.h"
+
 #include "ConfigDescription.h"
 #include "util/BigBuffer.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
@@ -149,14 +150,14 @@
    * Adds a string to the pool, unless it already exists. Returns
    * a reference to the string in the pool.
    */
-  Ref MakeRef(const StringPiece& str);
+  Ref MakeRef(const android::StringPiece& str);
 
   /**
    * Adds a string to the pool, unless it already exists, with a context
    * object that can be used when sorting the string pool. Returns
    * a reference to the string in the pool.
    */
-  Ref MakeRef(const StringPiece& str, const Context& context);
+  Ref MakeRef(const android::StringPiece& str, const Context& context);
 
   /**
    * Adds a style to the string pool and returns a reference to it.
@@ -208,11 +209,11 @@
 
   static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8);
 
-  Ref MakeRefImpl(const StringPiece& str, const Context& context, bool unique);
+  Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
 
   std::vector<std::unique_ptr<Entry>> strings_;
   std::vector<std::unique_ptr<StyleEntry>> styles_;
-  std::unordered_multimap<StringPiece, Entry*> indexed_strings_;
+  std::unordered_multimap<android::StringPiece, Entry*> indexed_strings_;
 };
 
 //
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index e1394fc..f64a8cf 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -18,9 +18,14 @@
 
 #include <string>
 
+#include "androidfw/StringPiece.h"
+
 #include "test/Test.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+using android::StringPiece16;
+
 namespace aapt {
 
 TEST(StringPoolTest, InsertOneString) {
@@ -236,8 +241,7 @@
     EXPECT_EQ(StringPiece16(u"goodbye"), util::GetString16(test, 1));
 
     EXPECT_EQ(StringPiece(sLongString), util::GetString(test, 2));
-    EXPECT_EQ(util::Utf8ToUtf16(sLongString),
-              util::GetString16(test, 2).ToString());
+    EXPECT_EQ(util::Utf8ToUtf16(sLongString), util::GetString16(test, 2).to_string());
 
     size_t len;
     EXPECT_TRUE(test.stringAt(3, &len) != nullptr ||
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index f0b18e6..8027f42 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -19,6 +19,12 @@
 #include <fstream>
 #include <string>
 
+#include "android-base/errors.h"
+#include "android-base/file.h"
+#include "androidfw/StringPiece.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+
 #include "ConfigDescription.h"
 #include "Diagnostics.h"
 #include "Flags.h"
@@ -38,11 +44,7 @@
 #include "xml/XmlDom.h"
 #include "xml/XmlPullParser.h"
 
-#include "android-base/errors.h"
-#include "android-base/file.h"
-#include "google/protobuf/io/coded_stream.h"
-#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
-
+using android::StringPiece;
 using google::protobuf::io::CopyingOutputStreamAdaptor;
 using google::protobuf::io::ZeroCopyOutputStream;
 
@@ -103,9 +105,8 @@
     name = name.substr(0, dot_pos);
   }
 
-  return ResourcePathData{Source(path),          dir_str.ToString(),
-                          name.ToString(),       extension.ToString(),
-                          config_str.ToString(), config};
+  return ResourcePathData{Source(path),          dir_str.to_string(),    name.to_string(),
+                          extension.to_string(), config_str.to_string(), config};
 }
 
 struct CompileOptions {
diff --git a/tools/aapt2/compile/IdAssigner.h b/tools/aapt2/compile/IdAssigner.h
index 371ec01..9640eb8 100644
--- a/tools/aapt2/compile/IdAssigner.h
+++ b/tools/aapt2/compile/IdAssigner.h
@@ -19,11 +19,11 @@
 
 #include <unordered_map>
 
+#include "android-base/macros.h"
+
 #include "Resource.h"
 #include "process/IResourceTableConsumer.h"
 
-#include "android-base/macros.h"
-
 namespace aapt {
 
 /**
@@ -40,8 +40,7 @@
   bool Consume(IAaptContext* context, ResourceTable* table) override;
 
  private:
-  const std::unordered_map<ResourceName, ResourceId>* assigned_id_map_ =
-      nullptr;
+  const std::unordered_map<ResourceName, ResourceId>* assigned_id_map_ = nullptr;
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/compile/NinePatch.cpp b/tools/aapt2/compile/NinePatch.cpp
index eab5c97..c931da4 100644
--- a/tools/aapt2/compile/NinePatch.cpp
+++ b/tools/aapt2/compile/NinePatch.cpp
@@ -21,10 +21,12 @@
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
 
-#include "util/StringPiece.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 // Colors in the format 0xAARRGGBB (the way 9-patch expects it).
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index 7ab05b5..5e15c88 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -15,18 +15,21 @@
  */
 
 #include "Png.h"
-#include "Source.h"
-#include "util/BigBuffer.h"
-#include "util/Util.h"
 
-#include <androidfw/ResourceTypes.h>
 #include <png.h>
 #include <zlib.h>
+
 #include <iostream>
 #include <sstream>
 #include <string>
 #include <vector>
 
+#include "androidfw/ResourceTypes.h"
+
+#include "Source.h"
+#include "util/BigBuffer.h"
+#include "util/Util.h"
+
 namespace aapt {
 
 constexpr bool kDebug = false;
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index aff1da3..a820051 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -56,7 +56,7 @@
  */
 class PngChunkFilter : public io::InputStream {
  public:
-  explicit PngChunkFilter(const StringPiece& data);
+  explicit PngChunkFilter(const android::StringPiece& data);
 
   bool Next(const void** buffer, int* len) override;
   void BackUp(int count) override;
@@ -71,7 +71,7 @@
  private:
   bool ConsumeWindow(const void** buffer, int* len);
 
-  StringPiece data_;
+  android::StringPiece data_;
   size_t window_start_ = 0;
   size_t window_end_ = 0;
   bool error_ = false;
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index 4cbefb9..edec123 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -16,8 +16,11 @@
 
 #include "compile/Png.h"
 
+#include "androidfw/StringPiece.h"
+
 #include "io/Io.h"
-#include "util/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 055a725..5035f81 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -23,6 +23,8 @@
 #include "ValueVisitor.h"
 #include "compile/Pseudolocalizer.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 std::unique_ptr<StyledString> PseudolocalizeStyledString(
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
index f89288f..15a3d8c 100644
--- a/tools/aapt2/compile/Pseudolocalizer.cpp
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -18,6 +18,8 @@
 
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 // String basis to generate expansion
@@ -40,10 +42,8 @@
 
 class PseudoMethodNone : public PseudoMethodImpl {
  public:
-  std::string Text(const StringPiece& text) override { return text.ToString(); }
-  std::string Placeholder(const StringPiece& text) override {
-    return text.ToString();
-  }
+  std::string Text(const StringPiece& text) override { return text.to_string(); }
+  std::string Placeholder(const StringPiece& text) override { return text.to_string(); }
 };
 
 class PseudoMethodBidi : public PseudoMethodImpl {
@@ -116,7 +116,7 @@
       }
       size_t size = nextpos - lastpos;
       if (size) {
-        std::string chunk = text.substr(lastpos, size).ToString();
+        std::string chunk = text.substr(lastpos, size).to_string();
         if (pseudo) {
           chunk = impl_->Text(chunk);
         } else if (str[lastpos] == kArgStart && str[nextpos - 1] == kArgEnd) {
@@ -437,7 +437,7 @@
 
 std::string PseudoMethodAccent::Placeholder(const StringPiece& source) {
   // Surround a placeholder with brackets
-  return kPlaceholderOpen + source.ToString() + kPlaceholderClose;
+  return kPlaceholderOpen + source.to_string() + kPlaceholderClose;
 }
 
 std::string PseudoMethodBidi::Text(const StringPiece& source) {
@@ -467,7 +467,7 @@
 
 std::string PseudoMethodBidi::Placeholder(const StringPiece& source) {
   // Surround a placeholder with directionality change sequence
-  return kRlm + kRlo + source.ToString() + kPdf + kRlm;
+  return kRlm + kRlo + source.to_string() + kPdf + kRlm;
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
index a6d2ad0..6cf003b 100644
--- a/tools/aapt2/compile/Pseudolocalizer.h
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -20,10 +20,10 @@
 #include <memory>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "ResourceValues.h"
 #include "StringPool.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
@@ -32,8 +32,8 @@
   virtual ~PseudoMethodImpl() {}
   virtual std::string Start() { return {}; }
   virtual std::string End() { return {}; }
-  virtual std::string Text(const StringPiece& text) = 0;
-  virtual std::string Placeholder(const StringPiece& text) = 0;
+  virtual std::string Text(const android::StringPiece& text) = 0;
+  virtual std::string Placeholder(const android::StringPiece& text) = 0;
 };
 
 class Pseudolocalizer {
@@ -48,7 +48,7 @@
   void SetMethod(Method method);
   std::string Start() { return impl_->Start(); }
   std::string End() { return impl_->End(); }
-  std::string Text(const StringPiece& text);
+  std::string Text(const android::StringPiece& text);
 
  private:
   std::unique_ptr<PseudoMethodImpl> impl_;
diff --git a/tools/aapt2/compile/Pseudolocalizer_test.cpp b/tools/aapt2/compile/Pseudolocalizer_test.cpp
index 92eb3b5..d3b7b02 100644
--- a/tools/aapt2/compile/Pseudolocalizer_test.cpp
+++ b/tools/aapt2/compile/Pseudolocalizer_test.cpp
@@ -19,6 +19,8 @@
 #include "test/Test.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 // In this context, 'Axis' represents a particular field in the configuration,
diff --git a/tools/aapt2/diff/Diff.cpp b/tools/aapt2/diff/Diff.cpp
index 593e7ab..de0fe40 100644
--- a/tools/aapt2/diff/Diff.cpp
+++ b/tools/aapt2/diff/Diff.cpp
@@ -24,6 +24,8 @@
 #include "process/SymbolTable.h"
 #include "unflatten/BinaryResourceParser.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 class DiffContext : public IAaptContext {
diff --git a/tools/aapt2/dump/Dump.cpp b/tools/aapt2/dump/Dump.cpp
index 2920c2a..bcede72 100644
--- a/tools/aapt2/dump/Dump.cpp
+++ b/tools/aapt2/dump/Dump.cpp
@@ -16,6 +16,8 @@
 
 #include <vector>
 
+#include "androidfw/StringPiece.h"
+
 #include "Debug.h"
 #include "Diagnostics.h"
 #include "Flags.h"
@@ -24,7 +26,8 @@
 #include "proto/ProtoSerialize.h"
 #include "unflatten/BinaryResourceParser.h"
 #include "util/Files.h"
-#include "util/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
diff --git a/tools/aapt2/flatten/Archive.cpp b/tools/aapt2/flatten/Archive.cpp
index 47de0a3..5c96a4d 100644
--- a/tools/aapt2/flatten/Archive.cpp
+++ b/tools/aapt2/flatten/Archive.cpp
@@ -22,10 +22,12 @@
 #include <vector>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 #include "ziparchive/zip_writer.h"
 
 #include "util/Files.h"
-#include "util/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
@@ -36,7 +38,7 @@
   DirectoryWriter() = default;
 
   bool Open(IDiagnostics* diag, const StringPiece& out_dir) {
-    dir_ = out_dir.ToString();
+    dir_ = out_dir.to_string();
     file::FileType type = file::GetFileType(dir_);
     if (type == file::FileType::kNonexistant) {
       diag->Error(DiagMessage() << "directory " << dir_ << " does not exist");
diff --git a/tools/aapt2/flatten/Archive.h b/tools/aapt2/flatten/Archive.h
index 4fcb3ff..f0681bd 100644
--- a/tools/aapt2/flatten/Archive.h
+++ b/tools/aapt2/flatten/Archive.h
@@ -22,12 +22,12 @@
 #include <string>
 #include <vector>
 
+#include "androidfw/StringPiece.h"
 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
 
 #include "Diagnostics.h"
 #include "util/BigBuffer.h"
 #include "util/Files.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
@@ -46,7 +46,7 @@
  public:
   virtual ~IArchiveWriter() = default;
 
-  virtual bool StartEntry(const StringPiece& path, uint32_t flags) = 0;
+  virtual bool StartEntry(const android::StringPiece& path, uint32_t flags) = 0;
   virtual bool WriteEntry(const BigBuffer& buffer) = 0;
   virtual bool WriteEntry(const void* data, size_t len) = 0;
   virtual bool FinishEntry() = 0;
@@ -57,11 +57,11 @@
   }
 };
 
-std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(
-    IDiagnostics* diag, const StringPiece& path);
+std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(IDiagnostics* diag,
+                                                             const android::StringPiece& path);
 
-std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(
-    IDiagnostics* diag, const StringPiece& path);
+std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(IDiagnostics* diag,
+                                                           const android::StringPiece& path);
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index 2c83bb3..ffc2de1 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -23,6 +23,8 @@
 #include "util/BigBuffer.h"
 #include "util/Util.h"
 
+using android::StringPiece16;
+
 namespace aapt {
 
 class XmlFlattenerTest : public ::testing::Test {
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 644f59f..3d5b5b1 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -110,7 +110,7 @@
  public:
   virtual ~IFileCollection() = default;
 
-  virtual IFile* FindFile(const StringPiece& path) = 0;
+  virtual IFile* FindFile(const android::StringPiece& path) = 0;
   virtual std::unique_ptr<IFileCollectionIterator> Iterator() = 0;
 };
 
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 828f34e..027cbd0 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -16,14 +16,16 @@
 
 #include "io/FileSystem.h"
 
+#include "androidfw/StringPiece.h"
 #include "utils/FileMap.h"
 
 #include "Source.h"
 #include "util/Files.h"
 #include "util/Maybe.h"
-#include "util/StringPiece.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 namespace io {
 
@@ -54,13 +56,11 @@
 }
 
 IFile* FileCollection::InsertFile(const StringPiece& path) {
-  return (files_[path.ToString()] =
-              util::make_unique<RegularFile>(Source(path)))
-      .get();
+  return (files_[path.to_string()] = util::make_unique<RegularFile>(Source(path))).get();
 }
 
 IFile* FileCollection::FindFile(const StringPiece& path) {
-  auto iter = files_.find(path.ToString());
+  auto iter = files_.find(path.to_string());
   if (iter != files_.end()) {
     return iter->second.get();
   }
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index 84f851f..dfd3717 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -59,8 +59,8 @@
   /**
    * Adds a file located at path. Returns the IFile representation of that file.
    */
-  IFile* InsertFile(const StringPiece& path);
-  IFile* FindFile(const StringPiece& path) override;
+  IFile* InsertFile(const android::StringPiece& path);
+  IFile* FindFile(const android::StringPiece& path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
 
  private:
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index f4a128e..62b436f 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -22,6 +22,8 @@
 #include "Source.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 namespace io {
 
@@ -107,7 +109,7 @@
     std::string zip_entry_path =
         std::string(reinterpret_cast<const char*>(zip_entry_name.name),
                     zip_entry_name.name_length);
-    std::string nested_path = path.ToString() + "@" + zip_entry_path;
+    std::string nested_path = path.to_string() + "@" + zip_entry_path;
     collection->files_[zip_entry_path] = util::make_unique<ZipFile>(
         collection->handle_, zip_data, Source(nested_path));
   }
@@ -120,7 +122,7 @@
 }
 
 IFile* ZipFileCollection::FindFile(const StringPiece& path) {
-  auto iter = files_.find(path.ToString());
+  auto iter = files_.find(path.to_string());
   if (iter != files_.end()) {
     return iter->second.get();
   }
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index 85ca1ae..634adad 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -21,8 +21,9 @@
 
 #include <map>
 
+#include "androidfw/StringPiece.h"
+
 #include "io/File.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 namespace io {
@@ -64,10 +65,10 @@
  */
 class ZipFileCollection : public IFileCollection {
  public:
-  static std::unique_ptr<ZipFileCollection> Create(const StringPiece& path,
+  static std::unique_ptr<ZipFileCollection> Create(const android::StringPiece& path,
                                                    std::string* outError);
 
-  io::IFile* FindFile(const StringPiece& path) override;
+  io::IFile* FindFile(const android::StringPiece& path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
 
   ~ZipFileCollection() override;
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 2951e5c..a0ef00b 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -20,6 +20,8 @@
 
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 void AnnotationProcessor::AppendCommentLine(std::string& comment) {
@@ -54,7 +56,7 @@
   for (StringPiece line : util::Tokenize(comment, '\n')) {
     line = util::TrimWhitespace(line);
     if (!line.empty()) {
-      std::string lineCopy = line.ToString();
+      std::string lineCopy = line.to_string();
       AppendCommentLine(lineCopy);
     }
   }
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index 666a7f3..99cd44f 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -20,7 +20,7 @@
 #include <sstream>
 #include <string>
 
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
 
 namespace aapt {
 
@@ -58,7 +58,7 @@
    * configurations,
    * we need to collect all the comments.
    */
-  void AppendComment(const StringPiece& comment);
+  void AppendComment(const android::StringPiece& comment);
 
   void AppendNewLine();
 
@@ -66,7 +66,7 @@
    * Writes the comments and annotations to the stream, with the given prefix
    * before each line.
    */
-  void WriteToStream(std::ostream* out, const StringPiece& prefix) const;
+  void WriteToStream(std::ostream* out, const android::StringPiece& prefix) const;
 
  private:
   enum : uint32_t {
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index f1f1f92..53d6ea1 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -16,7 +16,9 @@
 
 #include "java/ClassDefinition.h"
 
-#include "util/StringPiece.h"
+#include "androidfw/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
@@ -43,7 +45,7 @@
   }
   *out << "final class " << name_ << " {\n";
 
-  std::string new_prefix = prefix.ToString();
+  std::string new_prefix = prefix.to_string();
   new_prefix.append(kIndent);
 
   for (const std::unique_ptr<ClassMember>& member : members_) {
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index d8b61d9..64e4b29 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -21,10 +21,10 @@
 #include <string>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "Resource.h"
 #include "java/AnnotationProcessor.h"
-#include "util/StringPiece.h"
 #include "util/Util.h"
 
 namespace aapt {
@@ -41,7 +41,7 @@
 
   virtual bool empty() const = 0;
 
-  virtual void WriteToStream(const StringPiece& prefix, bool final,
+  virtual void WriteToStream(const android::StringPiece& prefix, bool final,
                              std::ostream* out) const {
     processor_.WriteToStream(out, prefix);
   }
@@ -53,12 +53,12 @@
 template <typename T>
 class PrimitiveMember : public ClassMember {
  public:
-  PrimitiveMember(const StringPiece& name, const T& val)
-      : name_(name.ToString()), val_(val) {}
+  PrimitiveMember(const android::StringPiece& name, const T& val)
+      : name_(name.to_string()), val_(val) {}
 
   bool empty() const override { return false; }
 
-  void WriteToStream(const StringPiece& prefix, bool final,
+  void WriteToStream(const android::StringPiece& prefix, bool final,
                      std::ostream* out) const override {
     ClassMember::WriteToStream(prefix, final, out);
 
@@ -79,12 +79,12 @@
 template <>
 class PrimitiveMember<std::string> : public ClassMember {
  public:
-  PrimitiveMember(const StringPiece& name, const std::string& val)
-      : name_(name.ToString()), val_(val) {}
+  PrimitiveMember(const android::StringPiece& name, const std::string& val)
+      : name_(name.to_string()), val_(val) {}
 
   bool empty() const override { return false; }
 
-  void WriteToStream(const StringPiece& prefix, bool final,
+  void WriteToStream(const android::StringPiece& prefix, bool final,
                      std::ostream* out) const override {
     ClassMember::WriteToStream(prefix, final, out);
 
@@ -106,14 +106,13 @@
 template <typename T>
 class PrimitiveArrayMember : public ClassMember {
  public:
-  explicit PrimitiveArrayMember(const StringPiece& name)
-      : name_(name.ToString()) {}
+  explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
 
   void AddElement(const T& val) { elements_.push_back(val); }
 
   bool empty() const override { return false; }
 
-  void WriteToStream(const StringPiece& prefix, bool final,
+  void WriteToStream(const android::StringPiece& prefix, bool final,
                      std::ostream* out) const override {
     ClassMember::WriteToStream(prefix, final, out);
 
@@ -147,22 +146,18 @@
 
 class ClassDefinition : public ClassMember {
  public:
-  static bool WriteJavaFile(const ClassDefinition* def,
-                            const StringPiece& package, bool final,
-                            std::ostream* out);
+  static bool WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
+                            bool final, std::ostream* out);
 
-  ClassDefinition(const StringPiece& name, ClassQualifier qualifier,
-                  bool createIfEmpty)
-      : name_(name.ToString()),
-        qualifier_(qualifier),
-        create_if_empty_(createIfEmpty) {}
+  ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
+      : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
 
   void AddMember(std::unique_ptr<ClassMember> member) {
     members_.push_back(std::move(member));
   }
 
   bool empty() const override;
-  void WriteToStream(const StringPiece& prefix, bool final,
+  void WriteToStream(const android::StringPiece& prefix, bool final,
                      std::ostream* out) const override;
 
  private:
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 6e7c7078..b71dc48 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -23,6 +23,7 @@
 #include <tuple>
 
 #include "android-base/logging.h"
+#include "androidfw/StringPiece.h"
 
 #include "NameMangler.h"
 #include "Resource.h"
@@ -32,7 +33,8 @@
 #include "java/AnnotationProcessor.h"
 #include "java/ClassDefinition.h"
 #include "process/SymbolTable.h"
-#include "util/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
@@ -58,7 +60,7 @@
  * Replace those with '_'.
  */
 static std::string Transform(const StringPiece& symbol) {
-  std::string output = symbol.ToString();
+  std::string output = symbol.to_string();
   for (char& c : output) {
     if (c == '.' || c == '-') {
       c = '_';
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 190e73b..5cf556e 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -20,10 +20,11 @@
 #include <ostream>
 #include <string>
 
+#include "androidfw/StringPiece.h"
+
 #include "ResourceTable.h"
 #include "ResourceValues.h"
 #include "process/IResourceTableConsumer.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 
@@ -69,22 +70,20 @@
    * We need to generate these symbols in a separate file.
    * Returns true on success.
    */
-  bool Generate(const StringPiece& packageNameToGenerate, std::ostream* out);
+  bool Generate(const android::StringPiece& packageNameToGenerate, std::ostream* out);
 
-  bool Generate(const StringPiece& packageNameToGenerate,
-                const StringPiece& outputPackageName, std::ostream* out);
+  bool Generate(const android::StringPiece& packageNameToGenerate,
+                const android::StringPiece& outputPackageName, std::ostream* out);
 
   const std::string& getError() const;
 
  private:
-  bool AddMembersToTypeClass(const StringPiece& packageNameToGenerate,
-                             const ResourceTablePackage* package,
-                             const ResourceTableType* type,
+  bool AddMembersToTypeClass(const android::StringPiece& packageNameToGenerate,
+                             const ResourceTablePackage* package, const ResourceTableType* type,
                              ClassDefinition* outTypeClassDef);
 
-  void AddMembersToStyleableClass(const StringPiece& packageNameToGenerate,
-                                  const std::string& entryName,
-                                  const Styleable* styleable,
+  void AddMembersToStyleableClass(const android::StringPiece& packageNameToGenerate,
+                                  const std::string& entryName, const Styleable* styleable,
                                   ClassDefinition* outStyleableClassDef);
 
   bool SkipSymbol(SymbolState state);
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 3d3d24e..55c5cb2 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -22,6 +22,8 @@
 #include "test/Test.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
diff --git a/tools/aapt2/java/ManifestClassGenerator.cpp b/tools/aapt2/java/ManifestClassGenerator.cpp
index db84f29..de8e59a 100644
--- a/tools/aapt2/java/ManifestClassGenerator.cpp
+++ b/tools/aapt2/java/ManifestClassGenerator.cpp
@@ -24,6 +24,8 @@
 #include "util/Maybe.h"
 #include "xml/XmlDom.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 static Maybe<StringPiece> ExtractJavaIdentifier(IDiagnostics* diag,
diff --git a/tools/aapt2/jni/aapt2_jni.cpp b/tools/aapt2/jni/aapt2_jni.cpp
index 5518fe2..b029b20 100644
--- a/tools/aapt2/jni/aapt2_jni.cpp
+++ b/tools/aapt2/jni/aapt2_jni.cpp
@@ -26,6 +26,8 @@
 
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 extern int Compile(const std::vector<StringPiece> &args);
 extern int Link(const std::vector<StringPiece> &args);
@@ -65,9 +67,8 @@
  * The returned pieces can only be used while the original ones have not been
  * destroyed.
  */
-static std::vector<aapt::StringPiece> extract_pieces(
-    const std::vector<ScopedUtfChars> &strings) {
-  std::vector<aapt::StringPiece> pieces;
+static std::vector<StringPiece> extract_pieces(const std::vector<ScopedUtfChars> &strings) {
+  std::vector<StringPiece> pieces;
 
   std::for_each(
       strings.begin(), strings.end(),
@@ -80,8 +81,7 @@
     JNIEnv *env, jclass aapt_obj, jobject arguments_obj) {
   std::vector<ScopedUtfChars> compile_args_jni =
       list_to_utfchars(env, arguments_obj);
-  std::vector<aapt::StringPiece> compile_args =
-      extract_pieces(compile_args_jni);
+  std::vector<StringPiece> compile_args = extract_pieces(compile_args_jni);
   aapt::Compile(compile_args);
 }
 
@@ -89,7 +89,7 @@
     JNIEnv *env, jclass aapt_obj, jobject arguments_obj) {
   std::vector<ScopedUtfChars> link_args_jni =
       list_to_utfchars(env, arguments_obj);
-  std::vector<aapt::StringPiece> link_args = extract_pieces(link_args_jni);
+  std::vector<StringPiece> link_args = extract_pieces(link_args_jni);
   aapt::Link(link_args);
 }
 
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index b525758..c3ce076 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -23,6 +23,7 @@
 
 #include "android-base/errors.h"
 #include "android-base/file.h"
+#include "androidfw/StringPiece.h"
 #include "google/protobuf/io/coded_stream.h"
 
 #include "AppInfo.h"
@@ -51,9 +52,9 @@
 #include "split/TableSplitter.h"
 #include "unflatten/BinaryResourceParser.h"
 #include "util/Files.h"
-#include "util/StringPiece.h"
 #include "xml/XmlDom.h"
 
+using android::StringPiece;
 using ::google::protobuf::io::CopyingOutputStreamAdaptor;
 
 namespace aapt {
@@ -121,7 +122,7 @@
   }
 
   void SetCompilationPackage(const StringPiece& package_name) {
-    compilation_package_ = package_name.ToString();
+    compilation_package_ = package_name.to_string();
   }
 
   uint8_t GetPackageId() override { return package_id_; }
@@ -2011,14 +2012,14 @@
   for (std::string& extra_package : extra_java_packages) {
     // A given package can actually be a colon separated list of packages.
     for (StringPiece package : util::Split(extra_package, ':')) {
-      options.extra_java_packages.insert(package.ToString());
+      options.extra_java_packages.insert(package.to_string());
     }
   }
 
   if (product_list) {
     for (StringPiece product : util::Tokenize(product_list.value(), ',')) {
       if (product != "" && product != "default") {
-        options.products.insert(product.ToString());
+        options.products.insert(product.to_string());
       }
     }
   }
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 4185937..e5eaf2f 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -25,6 +25,8 @@
 #include "xml/XmlActionExecutor.h"
 #include "xml/XmlDom.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 /**
@@ -293,7 +295,7 @@
   CHECK(attr != nullptr);
 
   std::string original_package = std::move(attr->value);
-  attr->value = package_override.ToString();
+  attr->value = package_override.to_string();
 
   FullyQualifiedClassNameVisitor visitor(original_package);
   manifest_el->Accept(&visitor);
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index fc6970c..12a304a 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -18,6 +18,8 @@
 
 #include "test/Test.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 struct ManifestFixerTest : public ::testing::Test {
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index be787b2..ea68b61 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -30,6 +30,8 @@
 #include "util/Util.h"
 #include "xml/XmlUtil.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 namespace {
@@ -192,8 +194,7 @@
       const StringPiece& alias,
       const StringPiece& local_package) const override {
     if (alias.empty()) {
-      return xml::ExtractedPackage{local_package.ToString(),
-                                   true /* private */};
+      return xml::ExtractedPackage{local_package.to_string(), true /* private */};
     }
     return {};
   }
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index d808da3..7e7b9fb 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -24,6 +24,8 @@
 #include "ValueVisitor.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 TableMerger::TableMerger(IAaptContext* context, ResourceTable* out_table,
@@ -351,9 +353,8 @@
     const std::string& package, const FileReference& file_ref) {
   StringPiece prefix, entry, suffix;
   if (util::ExtractResFilePathParts(*file_ref.path, &prefix, &entry, &suffix)) {
-    std::string mangled_entry =
-        NameMangler::MangleEntry(package, entry.ToString());
-    std::string newPath = prefix.ToString() + mangled_entry + suffix.ToString();
+    std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string());
+    std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string();
     std::unique_ptr<FileReference> new_file_ref =
         util::make_unique<FileReference>(
             master_table_->string_pool.MakeRef(newPath));
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 4ab83c3..c96b1b0 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -96,8 +96,8 @@
    * An io::IFileCollection is needed in order to find the referenced Files and
    * process them.
    */
-  bool MergeAndMangle(const Source& src, const StringPiece& package,
-                      ResourceTable* table, io::IFileCollection* collection);
+  bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table,
+                      io::IFileCollection* collection);
 
   /**
    * Merges a compiled file that belongs to this same or empty package. This is
diff --git a/tools/aapt2/link/VersionCollapser_test.cpp b/tools/aapt2/link/VersionCollapser_test.cpp
index 1b5592f..44babb2 100644
--- a/tools/aapt2/link/VersionCollapser_test.cpp
+++ b/tools/aapt2/link/VersionCollapser_test.cpp
@@ -18,6 +18,8 @@
 
 #include "test/Test.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 static std::unique_ptr<ResourceTable> BuildTableWithConfigs(
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 767384d..1a3da73 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -25,6 +25,8 @@
 #include "ValueVisitor.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 void SymbolTable::AppendSource(std::unique_ptr<ISymbolSource> source) {
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 25f7565..cf597bb 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -154,7 +154,7 @@
  public:
   AssetManagerSymbolSource() = default;
 
-  bool AddAssetPath(const StringPiece& path);
+  bool AddAssetPath(const android::StringPiece& path);
 
   std::unique_ptr<SymbolTable::Symbol> FindByName(
       const ResourceName& name) override;
diff --git a/tools/aapt2/proto/TableProtoSerializer.cpp b/tools/aapt2/proto/TableProtoSerializer.cpp
index 0d0e46d..7230b55 100644
--- a/tools/aapt2/proto/TableProtoSerializer.cpp
+++ b/tools/aapt2/proto/TableProtoSerializer.cpp
@@ -22,7 +22,7 @@
 #include "proto/ProtoSerialize.h"
 #include "util/BigBuffer.h"
 
-#include <android-base/logging.h>
+#include "android-base/logging.h"
 
 using google::protobuf::io::CodedOutputStream;
 using google::protobuf::io::CodedInputStream;
@@ -239,7 +239,7 @@
       if (type->id) {
         pb_type->set_id(type->id.value());
       }
-      pb_type->set_name(ToString(type->type).ToString());
+      pb_type->set_name(ToString(type->type).to_string());
 
       for (auto& entry : type->entries) {
         pb::Entry* pb_entry = pb_type->add_entries();
diff --git a/tools/aapt2/split/TableSplitter.cpp b/tools/aapt2/split/TableSplitter.cpp
index 7aad86f..38cfd2e 100644
--- a/tools/aapt2/split/TableSplitter.cpp
+++ b/tools/aapt2/split/TableSplitter.cpp
@@ -21,6 +21,7 @@
 #include <set>
 #include <unordered_map>
 #include <vector>
+
 #include "android-base/logging.h"
 
 #include "ConfigDescription.h"
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 9377306..6888cf3 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -37,95 +37,86 @@
 
   StringPool* string_pool() { return &table_->string_pool; }
 
-  ResourceTableBuilder& SetPackageId(const StringPiece& package_name,
-                                     uint8_t id) {
+  ResourceTableBuilder& SetPackageId(const android::StringPiece& package_name, uint8_t id) {
     ResourceTablePackage* package = table_->CreatePackage(package_name, id);
     CHECK(package != nullptr);
     return *this;
   }
 
-  ResourceTableBuilder& AddSimple(const StringPiece& name,
-                                  const ResourceId& id = {}) {
+  ResourceTableBuilder& AddSimple(const android::StringPiece& name, const ResourceId& id = {}) {
     return AddValue(name, id, util::make_unique<Id>());
   }
 
-  ResourceTableBuilder& AddSimple(const StringPiece& name,
-                                  const ConfigDescription& config,
+  ResourceTableBuilder& AddSimple(const android::StringPiece& name, const ConfigDescription& config,
                                   const ResourceId& id = {}) {
     return AddValue(name, config, id, util::make_unique<Id>());
   }
 
-  ResourceTableBuilder& AddReference(const StringPiece& name,
-                                     const StringPiece& ref) {
+  ResourceTableBuilder& AddReference(const android::StringPiece& name,
+                                     const android::StringPiece& ref) {
     return AddReference(name, {}, ref);
   }
 
-  ResourceTableBuilder& AddReference(const StringPiece& name,
-                                     const ResourceId& id,
-                                     const StringPiece& ref) {
+  ResourceTableBuilder& AddReference(const android::StringPiece& name, const ResourceId& id,
+                                     const android::StringPiece& ref) {
     return AddValue(name, id,
                     util::make_unique<Reference>(ParseNameOrDie(ref)));
   }
 
-  ResourceTableBuilder& AddString(const StringPiece& name,
-                                  const StringPiece& str) {
+  ResourceTableBuilder& AddString(const android::StringPiece& name,
+                                  const android::StringPiece& str) {
     return AddString(name, {}, str);
   }
 
-  ResourceTableBuilder& AddString(const StringPiece& name, const ResourceId& id,
-                                  const StringPiece& str) {
+  ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
+                                  const android::StringPiece& str) {
     return AddValue(
         name, id, util::make_unique<String>(table_->string_pool.MakeRef(str)));
   }
 
-  ResourceTableBuilder& AddString(const StringPiece& name, const ResourceId& id,
+  ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
                                   const ConfigDescription& config,
-                                  const StringPiece& str) {
+                                  const android::StringPiece& str) {
     return AddValue(name, config, id, util::make_unique<String>(
                                           table_->string_pool.MakeRef(str)));
   }
 
-  ResourceTableBuilder& AddFileReference(const StringPiece& name,
-                                         const StringPiece& path) {
+  ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
+                                         const android::StringPiece& path) {
     return AddFileReference(name, {}, path);
   }
 
-  ResourceTableBuilder& AddFileReference(const StringPiece& name,
-                                         const ResourceId& id,
-                                         const StringPiece& path) {
+  ResourceTableBuilder& AddFileReference(const android::StringPiece& name, const ResourceId& id,
+                                         const android::StringPiece& path) {
     return AddValue(name, id, util::make_unique<FileReference>(
                                   table_->string_pool.MakeRef(path)));
   }
 
-  ResourceTableBuilder& AddFileReference(const StringPiece& name,
-                                         const StringPiece& path,
+  ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
+                                         const android::StringPiece& path,
                                          const ConfigDescription& config) {
     return AddValue(name, config, {}, util::make_unique<FileReference>(
                                           table_->string_pool.MakeRef(path)));
   }
 
-  ResourceTableBuilder& AddValue(const StringPiece& name,
-                                 std::unique_ptr<Value> value) {
+  ResourceTableBuilder& AddValue(const android::StringPiece& name, std::unique_ptr<Value> value) {
     return AddValue(name, {}, std::move(value));
   }
 
-  ResourceTableBuilder& AddValue(const StringPiece& name, const ResourceId& id,
+  ResourceTableBuilder& AddValue(const android::StringPiece& name, const ResourceId& id,
                                  std::unique_ptr<Value> value) {
     return AddValue(name, {}, id, std::move(value));
   }
 
-  ResourceTableBuilder& AddValue(const StringPiece& name,
-                                 const ConfigDescription& config,
-                                 const ResourceId& id,
-                                 std::unique_ptr<Value> value) {
+  ResourceTableBuilder& AddValue(const android::StringPiece& name, const ConfigDescription& config,
+                                 const ResourceId& id, std::unique_ptr<Value> value) {
     ResourceName res_name = ParseNameOrDie(name);
     CHECK(table_->AddResourceAllowMangled(res_name, id, config, {},
                                           std::move(value), &diagnostics_));
     return *this;
   }
 
-  ResourceTableBuilder& SetSymbolState(const StringPiece& name,
-                                       const ResourceId& id,
+  ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
                                        SymbolState state) {
     ResourceName res_name = ParseNameOrDie(name);
     Symbol symbol;
@@ -144,8 +135,8 @@
   std::unique_ptr<ResourceTable> table_ = util::make_unique<ResourceTable>();
 };
 
-inline std::unique_ptr<Reference> BuildReference(
-    const StringPiece& ref, const Maybe<ResourceId>& id = {}) {
+inline std::unique_ptr<Reference> BuildReference(const android::StringPiece& ref,
+                                                 const Maybe<ResourceId>& id = {}) {
   std::unique_ptr<Reference> reference =
       util::make_unique<Reference>(ParseNameOrDie(ref));
   reference->id = id;
@@ -174,7 +165,7 @@
     return *this;
   }
 
-  ValueBuilder& SetComment(const StringPiece& str) {
+  ValueBuilder& SetComment(const android::StringPiece& str) {
     value_->SetComment(str);
     return *this;
   }
@@ -199,7 +190,7 @@
     return *this;
   }
 
-  AttributeBuilder& AddItem(const StringPiece& name, uint32_t value) {
+  AttributeBuilder& AddItem(const android::StringPiece& name, uint32_t value) {
     attr_->symbols.push_back(Attribute::Symbol{
         Reference(ResourceName({}, ResourceType::kId, name)), value});
     return *this;
@@ -217,18 +208,18 @@
  public:
   StyleBuilder() = default;
 
-  StyleBuilder& SetParent(const StringPiece& str) {
+  StyleBuilder& SetParent(const android::StringPiece& str) {
     style_->parent = Reference(ParseNameOrDie(str));
     return *this;
   }
 
-  StyleBuilder& AddItem(const StringPiece& str, std::unique_ptr<Item> value) {
+  StyleBuilder& AddItem(const android::StringPiece& str, std::unique_ptr<Item> value) {
     style_->entries.push_back(
         Style::Entry{Reference(ParseNameOrDie(str)), std::move(value)});
     return *this;
   }
 
-  StyleBuilder& AddItem(const StringPiece& str, const ResourceId& id,
+  StyleBuilder& AddItem(const android::StringPiece& str, const ResourceId& id,
                         std::unique_ptr<Item> value) {
     AddItem(str, std::move(value));
     style_->entries.back().key.id = id;
@@ -247,8 +238,7 @@
  public:
   StyleableBuilder() = default;
 
-  StyleableBuilder& AddItem(const StringPiece& str,
-                            const Maybe<ResourceId>& id = {}) {
+  StyleableBuilder& AddItem(const android::StringPiece& str, const Maybe<ResourceId>& id = {}) {
     styleable_->entries.push_back(Reference(ParseNameOrDie(str)));
     styleable_->entries.back().id = id;
     return *this;
@@ -262,7 +252,7 @@
   std::unique_ptr<Styleable> styleable_ = util::make_unique<Styleable>();
 };
 
-inline std::unique_ptr<xml::XmlResource> BuildXmlDom(const StringPiece& str) {
+inline std::unique_ptr<xml::XmlResource> BuildXmlDom(const android::StringPiece& str) {
   std::stringstream in;
   in << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" << str;
   StdErrDiagnostics diag;
@@ -273,7 +263,7 @@
 }
 
 inline std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(
-    IAaptContext* context, const StringPiece& str) {
+    IAaptContext* context, const android::StringPiece& str) {
   std::unique_ptr<xml::XmlResource> doc = BuildXmlDom(str);
   doc->file.name.package = context->GetCompilationPackage();
   return doc;
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 3689201..248921f 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -21,6 +21,7 @@
 
 #include "android-base/logging.h"
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 #include "gtest/gtest.h"
 
 #include "ConfigDescription.h"
@@ -30,7 +31,6 @@
 #include "ValueVisitor.h"
 #include "io/File.h"
 #include "process/IResourceTableConsumer.h"
-#include "util/StringPiece.h"
 
 //
 // GTEST 1.7 doesn't explicitly cast to bool, which causes explicit operators to
@@ -68,23 +68,22 @@
   return &diag;
 }
 
-inline ResourceName ParseNameOrDie(const StringPiece& str) {
+inline ResourceName ParseNameOrDie(const android::StringPiece& str) {
   ResourceNameRef ref;
   CHECK(ResourceUtils::ParseResourceName(str, &ref)) << "invalid resource name";
   return ref.ToResourceName();
 }
 
-inline ConfigDescription ParseConfigOrDie(const StringPiece& str) {
+inline ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
   ConfigDescription config;
   CHECK(ConfigDescription::Parse(str, &config)) << "invalid configuration";
   return config;
 }
 
 template <typename T>
-T* GetValueForConfigAndProduct(ResourceTable* table,
-                               const StringPiece& res_name,
+T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name,
                                const ConfigDescription& config,
-                               const StringPiece& product) {
+                               const android::StringPiece& product) {
   Maybe<ResourceTable::SearchResult> result =
       table->FindResource(ParseNameOrDie(res_name));
   if (result) {
@@ -98,19 +97,19 @@
 }
 
 template <typename T>
-T* GetValueForConfig(ResourceTable* table, const StringPiece& res_name,
+T* GetValueForConfig(ResourceTable* table, const android::StringPiece& res_name,
                      const ConfigDescription& config) {
   return GetValueForConfigAndProduct<T>(table, res_name, config, {});
 }
 
 template <typename T>
-T* GetValue(ResourceTable* table, const StringPiece& res_name) {
+T* GetValue(ResourceTable* table, const android::StringPiece& res_name) {
   return GetValueForConfig<T>(table, res_name, {});
 }
 
 class TestFile : public io::IFile {
  public:
-  explicit TestFile(const StringPiece& path) : source_(path) {}
+  explicit TestFile(const android::StringPiece& path) : source_(path) {}
 
   std::unique_ptr<io::IData> OpenAsData() override { return {}; }
 
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 7986329..63e5f16 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -70,8 +70,8 @@
 
 class ContextBuilder {
  public:
-  ContextBuilder& SetCompilationPackage(const StringPiece& package) {
-    context_->compilation_package_ = package.ToString();
+  ContextBuilder& SetCompilationPackage(const android::StringPiece& package) {
+    context_->compilation_package_ = package.to_string();
     return *this;
   }
 
@@ -103,9 +103,8 @@
 
 class StaticSymbolSourceBuilder {
  public:
-  StaticSymbolSourceBuilder& AddPublicSymbol(
-      const StringPiece& name, ResourceId id,
-      std::unique_ptr<Attribute> attr = {}) {
+  StaticSymbolSourceBuilder& AddPublicSymbol(const android::StringPiece& name, ResourceId id,
+                                             std::unique_ptr<Attribute> attr = {}) {
     std::unique_ptr<SymbolTable::Symbol> symbol =
         util::make_unique<SymbolTable::Symbol>(id, std::move(attr), true);
     symbol_source_->name_map_[ParseNameOrDie(name)] = symbol.get();
@@ -114,7 +113,7 @@
     return *this;
   }
 
-  StaticSymbolSourceBuilder& AddSymbol(const StringPiece& name, ResourceId id,
+  StaticSymbolSourceBuilder& AddSymbol(const android::StringPiece& name, ResourceId id,
                                        std::unique_ptr<Attribute> attr = {}) {
     std::unique_ptr<SymbolTable::Symbol> symbol =
         util::make_unique<SymbolTable::Symbol>(id, std::move(attr), false);
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index f034607..aa840e2 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -35,6 +35,8 @@
 #include <direct.h>
 #endif
 
+using android::StringPiece;
+
 namespace aapt {
 namespace file {
 
@@ -72,10 +74,9 @@
 
 inline static int MkdirImpl(const StringPiece& path) {
 #ifdef _WIN32
-  return _mkdir(path.ToString().c_str());
+  return _mkdir(path.to_string().c_str());
 #else
-  return mkdir(path.ToString().c_str(),
-               S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP);
+  return mkdir(path.to_string().c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP);
 #endif
 }
 
@@ -184,7 +185,7 @@
                         std::vector<std::string>* out_arglist,
                         std::string* out_error) {
   std::string contents;
-  if (!android::base::ReadFileToString(path.ToString(), &contents)) {
+  if (!android::base::ReadFileToString(path.to_string(), &contents)) {
     if (out_error) *out_error = "failed to read argument-list file";
     return false;
   }
@@ -192,7 +193,7 @@
   for (StringPiece line : util::Tokenize(contents, ' ')) {
     line = util::TrimWhitespace(line);
     if (!line.empty()) {
-      out_arglist->push_back(line.ToString());
+      out_arglist->push_back(line.to_string());
     }
   }
   return true;
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index a157dbd..95c492f 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -22,12 +22,12 @@
 #include <vector>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 #include "utils/FileMap.h"
 
 #include "Diagnostics.h"
 #include "Maybe.h"
 #include "Source.h"
-#include "util/StringPiece.h"
 
 namespace aapt {
 namespace file {
@@ -50,51 +50,49 @@
   kSocket,
 };
 
-FileType GetFileType(const StringPiece& path);
+FileType GetFileType(const android::StringPiece& path);
 
 /*
  * Appends a path to `base`, separated by the directory separator.
  */
-void AppendPath(std::string* base, StringPiece part);
+void AppendPath(std::string* base, android::StringPiece part);
 
 /*
  * Makes all the directories in `path`. The last element in the path
  * is interpreted as a directory.
  */
-bool mkdirs(const StringPiece& path);
+bool mkdirs(const android::StringPiece& path);
 
 /**
  * Returns all but the last part of the path.
  */
-StringPiece GetStem(const StringPiece& path);
+android::StringPiece GetStem(const android::StringPiece& path);
 
 /**
  * Returns the last part of the path with extension.
  */
-StringPiece GetFilename(const StringPiece& path);
+android::StringPiece GetFilename(const android::StringPiece& path);
 
 /**
  * Returns the extension of the path. This is the entire string after
  * the first '.' of the last part of the path.
  */
-StringPiece GetExtension(const StringPiece& path);
+android::StringPiece GetExtension(const android::StringPiece& path);
 
 /**
  * Converts a package name (com.android.app) to a path: com/android/app
  */
-std::string PackageToPath(const StringPiece& package);
+std::string PackageToPath(const android::StringPiece& package);
 
 /**
  * Creates a FileMap for the file at path.
  */
-Maybe<android::FileMap> MmapPath(const StringPiece& path,
-                                 std::string* out_error);
+Maybe<android::FileMap> MmapPath(const android::StringPiece& path, std::string* out_error);
 
 /**
  * Reads the file at path and appends each line to the outArgList vector.
  */
-bool AppendArgsFromFile(const StringPiece& path,
-                        std::vector<std::string>* out_arglist,
+bool AppendArgsFromFile(const android::StringPiece& path, std::vector<std::string>* out_arglist,
                         std::string* out_error);
 
 /*
@@ -120,7 +118,7 @@
    * - Otherwise the full string is matched.
    * - match is not case-sensitive.
    */
-  bool SetPattern(const StringPiece& pattern);
+  bool SetPattern(const android::StringPiece& pattern);
 
   /**
    * Applies the filter, returning true for pass, false for fail.
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index d5c0c8a..cf22322 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -15,9 +15,6 @@
  */
 
 #include "util/Util.h"
-#include "util/BigBuffer.h"
-#include "util/Maybe.h"
-#include "util/StringPiece.h"
 
 #include <utils/Unicode.h>
 #include <algorithm>
@@ -25,6 +22,14 @@
 #include <string>
 #include <vector>
 
+#include "androidfw/StringPiece.h"
+
+#include "util/BigBuffer.h"
+#include "util/Maybe.h"
+
+using android::StringPiece;
+using android::StringPiece16;
+
 namespace aapt {
 namespace util {
 
@@ -36,7 +41,7 @@
   StringPiece::const_iterator current;
   do {
     current = std::find(start, end, sep);
-    parts.emplace_back(str.substr(start, current).ToString());
+    parts.emplace_back(str.substr(start, current).to_string());
     if (f) {
       std::string& part = parts.back();
       std::transform(part.begin(), part.end(), part.begin(), f);
@@ -162,7 +167,7 @@
   }
 
   if (util::IsJavaClassName(classname)) {
-    return classname.ToString();
+    return classname.to_string();
   }
 
   if (package.empty()) {
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 05e9cc5..f8fa80e 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -24,11 +24,11 @@
 #include <vector>
 
 #include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
 #include "utils/ByteOrder.h"
 
 #include "util/BigBuffer.h"
 #include "util/Maybe.h"
-#include "util/StringPiece.h"
 
 #ifdef _WIN32
 // TODO(adamlesinski): remove once http://b/32447322 is resolved.
@@ -44,26 +44,24 @@
 namespace aapt {
 namespace util {
 
-std::vector<std::string> Split(const StringPiece& str, char sep);
-std::vector<std::string> SplitAndLowercase(const StringPiece& str, char sep);
+std::vector<std::string> Split(const android::StringPiece& str, char sep);
+std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
 
 /**
  * Returns true if the string starts with prefix.
  */
-bool StartsWith(const StringPiece& str, const StringPiece& prefix);
+bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);
 
 /**
  * Returns true if the string ends with suffix.
  */
-bool EndsWith(const StringPiece& str, const StringPiece& suffix);
+bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
 
 /**
  * Creates a new StringPiece16 that points to a substring
  * of the original string without leading or trailing whitespace.
  */
-StringPiece TrimWhitespace(const StringPiece& str);
-
-StringPiece TrimWhitespace(const StringPiece& str);
+android::StringPiece TrimWhitespace(const android::StringPiece& str);
 
 /**
  * UTF-16 isspace(). It basically checks for lower range characters that are
@@ -75,18 +73,18 @@
  * Returns an iterator to the first character that is not alpha-numeric and that
  * is not in the allowedChars set.
  */
-StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
-    const StringPiece& str, const StringPiece& allowed_chars);
+android::StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
+    const android::StringPiece& str, const android::StringPiece& allowed_chars);
 
 /**
  * Tests that the string is a valid Java class name.
  */
-bool IsJavaClassName(const StringPiece& str);
+bool IsJavaClassName(const android::StringPiece& str);
 
 /**
  * Tests that the string is a valid Java package name.
  */
-bool IsJavaPackageName(const StringPiece& str);
+bool IsJavaPackageName(const android::StringPiece& str);
 
 /**
  * Converts the class name to a fully qualified class name from the given
@@ -97,8 +95,8 @@
  * .a.b         --> package.a.b
  * asdf.adsf    --> asdf.adsf
  */
-Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
-                                              const StringPiece& class_name);
+Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
+                                              const android::StringPiece& class_name);
 
 /**
  * Makes a std::unique_ptr<> with the template parameter inferred by the
@@ -138,7 +136,7 @@
  * stored as UTF-8,
  * the conversion to UTF-16 happens within ResStringPool.
  */
-StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
+android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
 
 /**
  * Helper method to extract a UTF-8 string from a StringPool. If the string is
@@ -159,11 +157,11 @@
  * which will
  * break the string interpolation.
  */
-bool VerifyJavaStringFormat(const StringPiece& str);
+bool VerifyJavaStringFormat(const android::StringPiece& str);
 
 class StringBuilder {
  public:
-  StringBuilder& Append(const StringPiece& str);
+  StringBuilder& Append(const android::StringPiece& str);
   const std::string& ToString() const;
   const std::string& Error() const;
 
@@ -194,8 +192,8 @@
 /**
  * Converts a UTF8 string to a UTF16 string.
  */
-std::u16string Utf8ToUtf16(const StringPiece& utf8);
-std::string Utf16ToUtf8(const StringPiece16& utf16);
+std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
+std::string Utf16ToUtf8(const android::StringPiece16& utf16);
 
 /**
  * Writes the entire BigBuffer to the output stream.
@@ -220,22 +218,22 @@
 
     iterator& operator++();
 
-    StringPiece operator*() { return token_; }
+    android::StringPiece operator*() { return token_; }
     bool operator==(const iterator& rhs) const;
     bool operator!=(const iterator& rhs) const;
 
    private:
     friend class Tokenizer;
 
-    iterator(StringPiece s, char sep, StringPiece tok, bool end);
+    iterator(android::StringPiece s, char sep, android::StringPiece tok, bool end);
 
-    StringPiece str_;
+    android::StringPiece str_;
     char separator_;
-    StringPiece token_;
+    android::StringPiece token_;
     bool end_;
   };
 
-  Tokenizer(StringPiece str, char sep);
+  Tokenizer(android::StringPiece str, char sep);
 
   iterator begin() { return begin_; }
 
@@ -246,9 +244,7 @@
   const iterator end_;
 };
 
-inline Tokenizer Tokenize(const StringPiece& str, char sep) {
-  return Tokenizer(str, sep);
-}
+inline Tokenizer Tokenize(const android::StringPiece& str, char sep) { return Tokenizer(str, sep); }
 
 inline uint16_t HostToDevice16(uint16_t value) { return htods(value); }
 
@@ -267,8 +263,8 @@
  *
  * Returns true if successful.
  */
-bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix,
-                             StringPiece* out_entry, StringPiece* out_suffix);
+bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
+                             android::StringPiece* out_entry, android::StringPiece* out_suffix);
 
 }  // namespace util
 
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index cac3de4..e49aee5 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -20,6 +20,8 @@
 
 #include "test/Test.h"
 
+using android::StringPiece;
+
 namespace aapt {
 
 TEST(UtilTest, TrimOnlyWhitespace) {
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 960d361..fab2f19 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -29,6 +29,9 @@
 #include "XmlPullParser.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+using android::StringPiece16;
+
 namespace aapt {
 namespace xml {
 
@@ -52,10 +55,10 @@
 
   if (*p == 0) {
     out_ns->clear();
-    *out_name = StringPiece(name).ToString();
+    out_name->assign(name);
   } else {
-    *out_ns = StringPiece(name, (p - name)).ToString();
-    *out_name = StringPiece(p + 1).ToString();
+    out_ns->assign(name, (p - name));
+    out_name->assign(p + 1);
   }
 }
 
@@ -83,11 +86,11 @@
 
   std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
   if (prefix) {
-    ns->namespace_prefix = StringPiece(prefix).ToString();
+    ns->namespace_prefix = prefix;
   }
 
   if (uri) {
-    ns->namespace_uri = StringPiece(uri).ToString();
+    ns->namespace_uri = uri;
   }
 
   AddToStack(stack, parser, std::move(ns));
@@ -117,7 +120,7 @@
   while (*attrs) {
     Attribute attribute;
     SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
-    attribute.value = StringPiece(*attrs++).ToString();
+    attribute.value = *attrs++;
 
     // Insert in sorted order.
     auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(),
@@ -153,14 +156,14 @@
     if (!currentParent->children.empty()) {
       Node* last_child = currentParent->children.back().get();
       if (Text* text = NodeCast<Text>(last_child)) {
-        text->text += StringPiece(s, len).ToString();
+        text->text.append(s, len);
         return;
       }
     }
   }
 
   std::unique_ptr<Text> text = util::make_unique<Text>();
-  text->text = StringPiece(s, len).ToString();
+  text->text.assign(s, len);
   AddToStack(stack, parser, std::move(text));
 }
 
@@ -495,15 +498,14 @@
 Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
     const StringPiece& alias, const StringPiece& local_package) const {
   if (alias.empty()) {
-    return ExtractedPackage{local_package.ToString(), false /* private */};
+    return ExtractedPackage{local_package.to_string(), false /* private */};
   }
 
   const auto rend = package_decls_.rend();
   for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
     if (alias == iter->prefix) {
       if (iter->package.package.empty()) {
-        return ExtractedPackage{local_package.ToString(),
-                                iter->package.private_namespace};
+        return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
       }
       return iter->package;
     }
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 720fe35..90cdfb6 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -22,10 +22,11 @@
 #include <string>
 #include <vector>
 
+#include "androidfw/StringPiece.h"
+
 #include "Diagnostics.h"
 #include "Resource.h"
 #include "ResourceValues.h"
-#include "util/StringPiece.h"
 #include "util/Util.h"
 #include "xml/XmlUtil.h"
 
@@ -100,13 +101,13 @@
   std::string name;
   std::vector<Attribute> attributes;
 
-  Attribute* FindAttribute(const StringPiece& ns, const StringPiece& name);
-  xml::Element* FindChild(const StringPiece& ns, const StringPiece& name);
-  xml::Element* FindChildWithAttribute(const StringPiece& ns,
-                                       const StringPiece& name,
-                                       const StringPiece& attr_ns,
-                                       const StringPiece& attr_name,
-                                       const StringPiece& attr_value);
+  Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
+  xml::Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
+  xml::Element* FindChildWithAttribute(const android::StringPiece& ns,
+                                       const android::StringPiece& name,
+                                       const android::StringPiece& attr_ns,
+                                       const android::StringPiece& attr_name,
+                                       const android::StringPiece& attr_value);
   std::vector<xml::Element*> GetChildElements();
   std::unique_ptr<Node> Clone() override;
 };
@@ -190,8 +191,7 @@
 
   void Visit(Namespace* ns) override;
   Maybe<ExtractedPackage> TransformPackageAlias(
-      const StringPiece& alias,
-      const StringPiece& local_package) const override;
+      const android::StringPiece& alias, const android::StringPiece& local_package) const override;
 
  private:
   struct PackageDecl {
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index e59fa86..c2a9c82 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -22,6 +22,8 @@
 #include "xml/XmlPullParser.h"
 #include "xml/XmlUtil.h"
 
+using android::StringPiece;
+
 namespace aapt {
 namespace xml {
 
@@ -136,15 +138,14 @@
 Maybe<ExtractedPackage> XmlPullParser::TransformPackageAlias(
     const StringPiece& alias, const StringPiece& local_package) const {
   if (alias.empty()) {
-    return ExtractedPackage{local_package.ToString(), false /* private */};
+    return ExtractedPackage{local_package.to_string(), false /* private */};
   }
 
   const auto end_iter = package_aliases_.rend();
   for (auto iter = package_aliases_.rbegin(); iter != end_iter; ++iter) {
     if (alias == iter->prefix) {
       if (iter->package.package.empty()) {
-        return ExtractedPackage{local_package.ToString(),
-                                iter->package.private_namespace};
+        return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
       }
       return iter->package;
     }
@@ -188,19 +189,18 @@
 /**
  * Extracts the namespace and name of an expanded element or attribute name.
  */
-static void SplitName(const char* name, std::string& out_ns,
-                      std::string& out_name) {
+static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
   const char* p = name;
   while (*p != 0 && *p != kXmlNamespaceSep) {
     p++;
   }
 
   if (*p == 0) {
-    out_ns = std::string();
-    out_name = name;
+    out_ns->clear();
+    out_name->assign(name);
   } else {
-    out_ns = StringPiece(name, (p - name)).ToString();
-    out_name = p + 1;
+    out_ns->assign(name, (p - name));
+    out_name->assign(p + 1);
   }
 }
 
@@ -224,11 +224,11 @@
   EventData data = {Event::kStartElement,
                     XML_GetCurrentLineNumber(parser->parser_),
                     parser->depth_++};
-  SplitName(name, data.data1, data.data2);
+  SplitName(name, &data.data1, &data.data2);
 
   while (*attrs) {
     Attribute attribute;
-    SplitName(*attrs++, attribute.namespace_uri, attribute.name);
+    SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
     attribute.value = *attrs++;
 
     // Insert in sorted order.
@@ -245,9 +245,8 @@
                                                  int len) {
   XmlPullParser* parser = reinterpret_cast<XmlPullParser*>(user_data);
 
-  parser->event_queue_.push(
-      EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_),
-                parser->depth_, StringPiece(s, len).ToString()});
+  parser->event_queue_.push(EventData{Event::kText, XML_GetCurrentLineNumber(parser->parser_),
+                                      parser->depth_, std::string(s, len)});
 }
 
 void XMLCALL XmlPullParser::EndElementHandler(void* user_data,
@@ -257,7 +256,7 @@
   EventData data = {Event::kEndElement,
                     XML_GetCurrentLineNumber(parser->parser_),
                     --(parser->depth_)};
-  SplitName(name, data.data1, data.data2);
+  SplitName(name, &data.data1, &data.data2);
 
   // Move the data into the queue (no copy).
   parser->event_queue_.push(std::move(data));
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index ff58d60..cdeeefd 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -28,11 +28,11 @@
 #include <vector>
 
 #include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
 
 #include "Resource.h"
 #include "process/IResourceTableConsumer.h"
 #include "util/Maybe.h"
-#include "util/StringPiece.h"
 #include "xml/XmlUtil.h"
 
 namespace aapt {
@@ -119,8 +119,7 @@
    * 'package' will be set to 'defaultPackage'.
    */
   Maybe<ExtractedPackage> TransformPackageAlias(
-      const StringPiece& alias,
-      const StringPiece& local_package) const override;
+      const android::StringPiece& alias, const android::StringPiece& local_package) const override;
 
   //
   // Remaining methods are for retrieving information about attributes
@@ -146,8 +145,7 @@
   const_iterator begin_attributes() const;
   const_iterator end_attributes() const;
   size_t attribute_count() const;
-  const_iterator FindAttribute(StringPiece namespace_uri,
-                               StringPiece name) const;
+  const_iterator FindAttribute(android::StringPiece namespace_uri, android::StringPiece name) const;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(XmlPullParser);
@@ -190,16 +188,16 @@
 /**
  * Finds the attribute in the current element within the global namespace.
  */
-Maybe<StringPiece> FindAttribute(const XmlPullParser* parser,
-                                 const StringPiece& name);
+Maybe<android::StringPiece> FindAttribute(const XmlPullParser* parser,
+                                          const android::StringPiece& name);
 
 /**
  * Finds the attribute in the current element within the global namespace. The
  * attribute's value
  * must not be the empty string.
  */
-Maybe<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
-                                         const StringPiece& name);
+Maybe<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
+                                                  const android::StringPiece& name);
 
 //
 // Implementation
@@ -299,13 +297,13 @@
 }
 
 inline XmlPullParser::const_iterator XmlPullParser::FindAttribute(
-    StringPiece namespace_uri, StringPiece name) const {
+    android::StringPiece namespace_uri, android::StringPiece name) const {
   const auto end_iter = end_attributes();
   const auto iter = std::lower_bound(
       begin_attributes(), end_iter,
-      std::pair<StringPiece, StringPiece>(namespace_uri, name),
+      std::pair<android::StringPiece, android::StringPiece>(namespace_uri, name),
       [](const Attribute& attr,
-         const std::pair<StringPiece, StringPiece>& rhs) -> bool {
+         const std::pair<android::StringPiece, android::StringPiece>& rhs) -> bool {
         int cmp = attr.namespace_uri.compare(
             0, attr.namespace_uri.size(), rhs.first.data(), rhs.first.size());
         if (cmp < 0) return true;
diff --git a/tools/aapt2/xml/XmlPullParser_test.cpp b/tools/aapt2/xml/XmlPullParser_test.cpp
index 4f18cd2..1cce485 100644
--- a/tools/aapt2/xml/XmlPullParser_test.cpp
+++ b/tools/aapt2/xml/XmlPullParser_test.cpp
@@ -18,8 +18,11 @@
 
 #include <sstream>
 
+#include "androidfw/StringPiece.h"
+
 #include "test/Test.h"
-#include "util/StringPiece.h"
+
+using android::StringPiece;
 
 namespace aapt {
 
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index d00f7f2..fb8cee8 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -21,6 +21,8 @@
 #include "util/Maybe.h"
 #include "util/Util.h"
 
+using android::StringPiece;
+
 namespace aapt {
 namespace xml {
 
@@ -42,7 +44,7 @@
     if (package.empty()) {
       return {};
     }
-    return ExtractedPackage{package.ToString(), false /* is_private */};
+    return ExtractedPackage{package.to_string(), false /* is_private */};
 
   } else if (util::StartsWith(namespace_uri, kSchemaPrivatePrefix)) {
     StringPiece schema_prefix = kSchemaPrivatePrefix;
@@ -52,7 +54,7 @@
     if (package.empty()) {
       return {};
     }
-    return ExtractedPackage{package.ToString(), true /* is_private */};
+    return ExtractedPackage{package.to_string(), true /* is_private */};
 
   } else if (namespace_uri == kSchemaAuto) {
     return ExtractedPackage{std::string(), true /* is_private */};
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 5365401..1650ac2 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -74,7 +74,7 @@
  *
  * http://schemas.android.com/apk/prv/res/<package>
  */
-std::string BuildPackageNamespace(const StringPiece& package,
+std::string BuildPackageNamespace(const android::StringPiece& package,
                                   bool private_reference = false);
 
 /**
@@ -90,7 +90,7 @@
    * package declaration.
    */
   virtual Maybe<ExtractedPackage> TransformPackageAlias(
-      const StringPiece& alias, const StringPiece& local_package) const = 0;
+      const android::StringPiece& alias, const android::StringPiece& local_package) const = 0;
 };
 
 /**
@@ -100,8 +100,7 @@
  * the namespace of the package declaration was private.
  */
 void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,
-                                     const StringPiece& local_package,
-                                     Reference* in_ref);
+                                     const android::StringPiece& local_package, Reference* in_ref);
 
 }  // namespace xml
 }  // namespace aapt
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index d326935..d0c9599 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.text.FontConfig;
 import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.layoutlib.bridge.Bridge;
@@ -248,17 +249,14 @@
     // ---- delegate methods ----
     @LayoutlibDelegate
     /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex) {
-        if (thisFontFamily.mBuilderPtr == 0) {
-            throw new IllegalStateException("Unable to call addFont after freezing.");
-        }
-        final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mBuilderPtr);
+        final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mNativePtr);
         return delegate != null && delegate.addFont(path, ttcIndex);
     }
 
     // ---- native methods ----
 
     @LayoutlibDelegate
-    /*package*/ static long nInitBuilder(String lang, int variant) {
+    /*package*/ static long nCreateFamily(String lang, int variant) {
         // TODO: support lang. This is required for japanese locale.
         FontFamily_Delegate delegate = new FontFamily_Delegate();
         // variant can be 0, 1 or 2.
@@ -273,11 +271,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static long nCreateFamily(long builderPtr) {
-        return builderPtr;
-    }
-
-    @LayoutlibDelegate
     /*package*/ static void nUnrefFamily(long nativePtr) {
         // Removing the java reference for the object doesn't mean that it's freed for garbage
         // collection. Typeface_Delegate may still hold a reference for it.
@@ -285,22 +278,22 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) {
+    /*package*/ static boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex) {
         assert false : "The only client of this method has been overriden.";
         return false;
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
-            int ttcIndex, List<FontListParser.Axis> listOfAxis,
+    /*package*/ static boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
+            int ttcIndex, List<FontConfig.Axis> listOfAxis,
             int weight, boolean isItalic) {
         assert false : "The only client of this method has been overriden.";
         return false;
     }
 
-    static boolean addFont(long builderPtr, final String path, final int weight,
+    static boolean addFont(long nativeFamily, final String path, final int weight,
             final boolean isItalic) {
-        final FontFamily_Delegate delegate = getDelegate(builderPtr);
+        final FontFamily_Delegate delegate = getDelegate(nativeFamily);
         if (delegate != null) {
             if (sFontLocation == null) {
                 delegate.mPostInitRunnables.add(() -> delegate.addFont(path, weight, isItalic));
@@ -312,8 +305,8 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nAddFontFromAsset(long builderPtr, AssetManager mgr, String path) {
-        FontFamily_Delegate ffd = sManager.getDelegate(builderPtr);
+    /*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
+        FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily);
         if (ffd == null) {
             return false;
         }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index a554b6d..6e337d5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.text.FontConfig;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
@@ -208,14 +209,13 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static FontFamily makeFamilyFromParsed(FontListParser.Family family,
+    /*package*/ static FontFamily makeFamilyFromParsed(FontConfig.Family family,
             Map<String, ByteBuffer> bufferForPath) {
-        FontFamily fontFamily = new FontFamily(family.lang, family.variant);
-        for (FontListParser.Font font : family.fonts) {
-            FontFamily_Delegate.addFont(fontFamily.mBuilderPtr, font.fontName, font.weight,
-                    font.isItalic);
+        FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
+        for (FontConfig.Font font : family.getFonts()) {
+            FontFamily_Delegate.addFont(fontFamily.mNativePtr, font.getFontName(),
+                    font.getWeight(), font.isItalic());
         }
-        fontFamily.freeze();
         return fontFamily;
     }
 
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 663e56d..68680d5 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
@@ -40,6 +40,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Notification;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -1820,6 +1821,13 @@
     }
 
     @Override
+    public ComponentName startServiceInForeground(Intent service,
+            int id, Notification notification) {
+        // pass
+        return null;
+    }
+
+    @Override
     public boolean stopService(Intent arg0) {
         // pass
         return false;
@@ -1832,6 +1840,13 @@
     }
 
     @Override
+    public ComponentName startServiceInForegroundAsUser(Intent service,
+            int id, Notification notification, UserHandle user) {
+        // pass
+        return null;
+    }
+
+    @Override
     public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
         // pass
         return false;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index bc7bc74..d3ec9e2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -42,14 +42,15 @@
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.VersionedPackage;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 import java.util.List;
@@ -71,6 +72,23 @@
     }
 
     @Override
+    public PackageInfo getPackageInfo(VersionedPackage versionedPackage,
+            @PackageInfoFlags int flags) throws NameNotFoundException {
+        return null;
+    }
+
+    @Override
+    public List<SharedLibraryInfo> getSharedLibraries(@InstallFlags int flags) {
+        return null;
+    }
+
+    @Override
+    public List<SharedLibraryInfo> getSharedLibrariesAsUser(@InstallFlags int flags,
+            int userId) {
+        return null;
+    }
+
+    @Override
     public String[] currentToCanonicalPackageNames(String[] names) {
         return new String[0];
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 741eb27..7ba86fd 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -339,8 +339,7 @@
      */
     private final static String[] PROMOTED_FIELDS = new String[] {
         "android.graphics.drawable.VectorDrawable#mVectorState",
-        "android.view.Choreographer#mLastFrameTimeNanos",
-        "android.graphics.FontFamily#mBuilderPtr"
+        "android.view.Choreographer#mLastFrameTimeNanos"
     };
 
     /**
diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py
index b071093..9dceba2 100755
--- a/tools/localedata/extract_icu_data.py
+++ b/tools/localedata/extract_icu_data.py
@@ -48,6 +48,8 @@
             # they may be used by apps for other purposes.)
             "en_XA": "~~~A",
             "ar_XB": "~~~B",
+            # Removed data from later versions of ICU
+            "ji": "Hebr", # Old code for Yiddish, still used in Java and Android
         }
         representative_locales = {
             # Android's additions
@@ -69,7 +71,7 @@
                 _, to_scr, to_region = get_locale_parts(to_locale)
                 if from_lang == 'und':
                     continue  # not very useful for our purposes
-                if from_region is None and to_region != '001':
+                if from_region is None and to_region not in ['001', 'ZZ']:
                     representative_locales.add(to_locale)
                 if from_scr is None:
                     likely_script_dict[from_locale] = to_scr
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3a45671..8cf7a24 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -709,6 +709,16 @@
 
     /**
      * @hide
+     * Indicate that a WifiConfiguration is temporary and should not be saved
+     * nor considered by AutoJoin.
+     */
+    @SystemApi
+    public boolean isEphemeral() {
+      return ephemeral;
+    }
+
+    /**
+     * @hide
      * A hint about whether or not the network represented by this WifiConfiguration
      * is metered. This is hinted at via the meteredHint bit on DHCP results set in
      * {@link com.android.server.wifi.WifiStateMachine}, or via a network score in
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index 71124bb..36e4717 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -43,7 +43,7 @@
  */
 public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
     private static final String TAG = "WifiNetworkScoreCache";
-    private static final boolean DBG = false;
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
     // A Network scorer returns a score in the range [-128, +127]
     // We treat the lowest possible score as though there were no score, effectively allowing the
@@ -83,18 +83,28 @@
         if (networks == null || networks.isEmpty()) {
            return;
         }
-        Log.d(TAG, "updateScores list size=" + networks.size());
+        if (DBG) {
+            Log.d(TAG, "updateScores list size=" + networks.size());
+        }
+
+        boolean changed = false;
 
         synchronized(mNetworkCache) {
             for (ScoredNetwork network : networks) {
                 String networkKey = buildNetworkKey(network);
-                if (networkKey == null) continue;
+                if (networkKey == null) {
+                    if (DBG) {
+                        Log.d(TAG, "Failed to build network key for ScoredNetwork" + network);
+                    }
+                    continue;
+                }
                 mNetworkCache.put(networkKey, network);
+                changed = true;
             }
         }
 
         synchronized (mCacheLock) {
-            if (mListener != null) {
+            if (mListener != null && changed) {
                 mListener.post(networks);
             }
         }
@@ -170,25 +180,49 @@
         return score;
     }
 
-    private ScoredNetwork getScoredNetwork(ScanResult result) {
+    @Nullable
+    public ScoredNetwork getScoredNetwork(ScanResult result) {
         String key = buildNetworkKey(result);
         if (key == null) return null;
 
-        //find it
         synchronized(mNetworkCache) {
             ScoredNetwork network = mNetworkCache.get(key);
             return network;
         }
     }
 
-     private String buildNetworkKey(ScoredNetwork network) {
-        if (network == null || network.networkKey == null) return null;
-        if (network.networkKey.wifiKey == null) return null;
-        if (network.networkKey.type == NetworkKey.TYPE_WIFI) {
-            String key = network.networkKey.wifiKey.ssid;
+    /** Returns the ScoredNetwork for the given key. */
+    @Nullable
+    public ScoredNetwork getScoredNetwork(NetworkKey networkKey) {
+        String key = buildNetworkKey(networkKey);
+        if (key == null) {
+            if (DBG) {
+                Log.d(TAG, "Could not build key string for Network Key: " + networkKey);
+            }
+            return null;
+        }
+        synchronized (mNetworkCache) {
+            return mNetworkCache.get(key);
+        }
+    }
+
+    private String buildNetworkKey(ScoredNetwork network) {
+        if (network == null) {
+            return null;
+        }
+        return buildNetworkKey(network.networkKey);
+    }
+
+    private String buildNetworkKey(NetworkKey networkKey) {
+        if (networkKey == null) {
+            return null;
+        }
+        if (networkKey.wifiKey == null) return null;
+        if (networkKey.type == NetworkKey.TYPE_WIFI) {
+            String key = networkKey.wifiKey.ssid;
             if (key == null) return null;
-            if (network.networkKey.wifiKey.bssid != null) {
-                key = key + network.networkKey.wifiKey.bssid;
+            if (networkKey.wifiKey.bssid != null) {
+                key = key + networkKey.wifiKey.bssid;
             }
             return key;
         }